mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-06 12:14:28 +08:00
fix OneToOneField without related_name
This commit is contained in:
@@ -116,6 +116,9 @@ class FloatField(Field[_ST, _GT]):
|
|||||||
class DecimalField(Field[_ST, _GT]):
|
class DecimalField(Field[_ST, _GT]):
|
||||||
_pyi_private_set_type: Union[str, float, decimal.Decimal, Combinable]
|
_pyi_private_set_type: Union[str, float, decimal.Decimal, Combinable]
|
||||||
_pyi_private_get_type: decimal.Decimal
|
_pyi_private_get_type: decimal.Decimal
|
||||||
|
# attributes
|
||||||
|
max_digits: int = ...
|
||||||
|
decimal_places: int = ...
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
verbose_name: Optional[Union[str, bytes]] = ...,
|
verbose_name: Optional[Union[str, bytes]] = ...,
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from typing import cast
|
from typing import cast, Type
|
||||||
|
|
||||||
|
from django.db.models.base import Model
|
||||||
from django.db.models.fields.related import ForeignKey
|
from django.db.models.fields.related import ForeignKey
|
||||||
from django.db.models.fields.reverse_related import ManyToManyRel, ManyToOneRel, OneToOneRel
|
from django.db.models.fields.reverse_related import ManyToManyRel, ManyToOneRel, OneToOneRel
|
||||||
from mypy.newsemanal.semanal import NewSemanticAnalyzer
|
from mypy.newsemanal.semanal import NewSemanticAnalyzer
|
||||||
@@ -45,9 +46,15 @@ class ModelClassInitializer(metaclass=ABCMeta):
|
|||||||
var.is_inferred = True
|
var.is_inferred = True
|
||||||
self.model_classdef.info.names[name] = SymbolTableNode(MDEF, var, plugin_generated=True)
|
self.model_classdef.info.names[name] = SymbolTableNode(MDEF, var, plugin_generated=True)
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
raise NotImplementedError()
|
model_cls = self.django_context.get_model_class_by_fullname(self.model_classdef.fullname)
|
||||||
|
if model_cls is None:
|
||||||
|
return
|
||||||
|
self.run_with_model_cls(model_cls)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def run_with_model_cls(self, model_cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InjectAnyAsBaseForNestedMeta(ModelClassInitializer):
|
class InjectAnyAsBaseForNestedMeta(ModelClassInitializer):
|
||||||
@@ -63,7 +70,7 @@ class InjectAnyAsBaseForNestedMeta(ModelClassInitializer):
|
|||||||
to get around incompatible Meta inner classes for different models.
|
to get around incompatible Meta inner classes for different models.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def run(self) -> None:
|
def run_with_model_cls(self, model_cls: Type[Model])-> None:
|
||||||
meta_node = helpers.get_nested_meta_node_for_current_class(self.model_classdef.info)
|
meta_node = helpers.get_nested_meta_node_for_current_class(self.model_classdef.info)
|
||||||
if meta_node is None:
|
if meta_node is None:
|
||||||
return None
|
return None
|
||||||
@@ -71,11 +78,7 @@ class InjectAnyAsBaseForNestedMeta(ModelClassInitializer):
|
|||||||
|
|
||||||
|
|
||||||
class AddDefaultPrimaryKey(ModelClassInitializer):
|
class AddDefaultPrimaryKey(ModelClassInitializer):
|
||||||
def run(self) -> None:
|
def run_with_model_cls(self, model_cls: Type[Model])-> None:
|
||||||
model_cls = self.django_context.get_model_class_by_fullname(self.model_classdef.fullname)
|
|
||||||
if model_cls is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
auto_field = model_cls._meta.auto_field
|
auto_field = model_cls._meta.auto_field
|
||||||
if auto_field and not self.model_classdef.info.has_readable_member(auto_field.attname):
|
if auto_field and not self.model_classdef.info.has_readable_member(auto_field.attname):
|
||||||
# autogenerated field
|
# autogenerated field
|
||||||
@@ -88,11 +91,7 @@ class AddDefaultPrimaryKey(ModelClassInitializer):
|
|||||||
|
|
||||||
|
|
||||||
class AddRelatedModelsId(ModelClassInitializer):
|
class AddRelatedModelsId(ModelClassInitializer):
|
||||||
def run(self) -> None:
|
def run_with_model_cls(self, model_cls: Type[Model])-> None:
|
||||||
model_cls = self.django_context.get_model_class_by_fullname(self.model_classdef.fullname)
|
|
||||||
if model_cls is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
for field in model_cls._meta.get_fields():
|
for field in model_cls._meta.get_fields():
|
||||||
if isinstance(field, ForeignKey):
|
if isinstance(field, ForeignKey):
|
||||||
rel_primary_key_field = self.django_context.get_primary_key_field(field.related_model)
|
rel_primary_key_field = self.django_context.get_primary_key_field(field.related_model)
|
||||||
@@ -104,11 +103,7 @@ class AddRelatedModelsId(ModelClassInitializer):
|
|||||||
|
|
||||||
|
|
||||||
class AddManagers(ModelClassInitializer):
|
class AddManagers(ModelClassInitializer):
|
||||||
def run(self):
|
def run_with_model_cls(self, model_cls: Type[Model])-> None:
|
||||||
model_cls = self.django_context.get_model_class_by_fullname(self.model_classdef.fullname)
|
|
||||||
if model_cls is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
for manager_name, manager in model_cls._meta.managers_map.items():
|
for manager_name, manager in model_cls._meta.managers_map.items():
|
||||||
if manager_name not in self.model_classdef.info.names:
|
if manager_name not in self.model_classdef.info.names:
|
||||||
manager_fullname = helpers.get_class_fullname(manager.__class__)
|
manager_fullname = helpers.get_class_fullname(manager.__class__)
|
||||||
@@ -126,14 +121,17 @@ class AddManagers(ModelClassInitializer):
|
|||||||
|
|
||||||
# add related managers
|
# add related managers
|
||||||
for relation in self.django_context.get_model_relations(model_cls):
|
for relation in self.django_context.get_model_relations(model_cls):
|
||||||
attname = relation.related_name
|
attname = relation.get_accessor_name()
|
||||||
if attname is None:
|
if attname is None:
|
||||||
attname = relation.name + '_set'
|
# no reverse accessor
|
||||||
|
continue
|
||||||
|
|
||||||
related_model_info = self.lookup_class_typeinfo_or_incomplete_defn_error(relation.related_model)
|
related_model_info = self.lookup_class_typeinfo_or_incomplete_defn_error(relation.related_model)
|
||||||
|
|
||||||
if isinstance(relation, OneToOneRel):
|
if isinstance(relation, OneToOneRel):
|
||||||
self.add_new_node_to_model_class(attname, Instance(related_model_info, []))
|
self.add_new_node_to_model_class(attname, Instance(related_model_info, []))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(relation, (ManyToOneRel, ManyToManyRel)):
|
if isinstance(relation, (ManyToOneRel, ManyToManyRel)):
|
||||||
manager_info = self.lookup_typeinfo_or_incomplete_defn_error(fullnames.RELATED_MANAGER_CLASS_FULLNAME)
|
manager_info = self.lookup_typeinfo_or_incomplete_defn_error(fullnames.RELATED_MANAGER_CLASS_FULLNAME)
|
||||||
self.add_new_node_to_model_class(attname,
|
self.add_new_node_to_model_class(attname,
|
||||||
@@ -142,11 +140,7 @@ class AddManagers(ModelClassInitializer):
|
|||||||
|
|
||||||
|
|
||||||
class AddExtraFieldMethods(ModelClassInitializer):
|
class AddExtraFieldMethods(ModelClassInitializer):
|
||||||
def run(self):
|
def run_with_model_cls(self, model_cls: Type[Model])-> None:
|
||||||
model_cls = self.django_context.get_model_class_by_fullname(self.model_classdef.fullname)
|
|
||||||
if model_cls is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
# get_FOO_display for choices
|
# get_FOO_display for choices
|
||||||
for field in self.django_context.get_model_fields(model_cls):
|
for field in self.django_context.get_model_fields(model_cls):
|
||||||
if field.choices:
|
if field.choices:
|
||||||
@@ -178,7 +172,7 @@ class AddExtraFieldMethods(ModelClassInitializer):
|
|||||||
|
|
||||||
|
|
||||||
class AddMetaOptionsAttribute(ModelClassInitializer):
|
class AddMetaOptionsAttribute(ModelClassInitializer):
|
||||||
def run(self):
|
def run_with_model_cls(self, model_cls: Type[Model])-> None:
|
||||||
if '_meta' not in self.model_classdef.info.names:
|
if '_meta' not in self.model_classdef.info.names:
|
||||||
options_info = self.lookup_typeinfo_or_incomplete_defn_error(fullnames.OPTIONS_CLASS_FULLNAME)
|
options_info = self.lookup_typeinfo_or_incomplete_defn_error(fullnames.OPTIONS_CLASS_FULLNAME)
|
||||||
self.add_new_node_to_model_class('_meta',
|
self.add_new_node_to_model_class('_meta',
|
||||||
|
|||||||
@@ -84,6 +84,23 @@
|
|||||||
class Book(models.Model):
|
class Book(models.Model):
|
||||||
publisher = models.ForeignKey(to='myapp.Publisher', on_delete=models.CASCADE)
|
publisher = models.ForeignKey(to='myapp.Publisher', on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
- case: one_to_one_field_no_related_name
|
||||||
|
main: |
|
||||||
|
from myapp.models import User, Profile
|
||||||
|
reveal_type(User().profile) # N: Revealed type is 'myapp.models.Profile'
|
||||||
|
reveal_type(Profile().user) # N: Revealed type is 'myapp.models.User*'
|
||||||
|
installed_apps:
|
||||||
|
- myapp
|
||||||
|
files:
|
||||||
|
- path: myapp/__init__.py
|
||||||
|
- path: myapp/models.py
|
||||||
|
content: |
|
||||||
|
from django.db import models
|
||||||
|
class User(models.Model):
|
||||||
|
pass
|
||||||
|
class Profile(models.Model):
|
||||||
|
user = models.OneToOneField(to=User, on_delete=models)
|
||||||
|
|
||||||
- case: test_circular_dependency_in_imports_with_foreign_key
|
- case: test_circular_dependency_in_imports_with_foreign_key
|
||||||
main: |
|
main: |
|
||||||
from myapp import models
|
from myapp import models
|
||||||
|
|||||||
Reference in New Issue
Block a user