diff --git a/mypy_django_plugin/transformers/querysets.py b/mypy_django_plugin/transformers/querysets.py index f7e7933d4..05b1dad3c 100644 --- a/mypy_django_plugin/transformers/querysets.py +++ b/mypy_django_plugin/transformers/querysets.py @@ -33,10 +33,14 @@ def determine_proper_manager_type(ctx: FunctionContext) -> MypyType: assert isinstance(default_return_type, Instance) outer_model_info = helpers.get_typechecker_api(ctx).scope.active_class() - if outer_model_info is None or not outer_model_info.has_base(fullnames.MODEL_CLASS_FULLNAME): + if ( + outer_model_info is None + or not outer_model_info.has_base(fullnames.MODEL_CLASS_FULLNAME) + or outer_model_info.self_type is None + ): return default_return_type - return helpers.reparametrize_instance(default_return_type, [Instance(outer_model_info, [])]) + return helpers.reparametrize_instance(default_return_type, [outer_model_info.self_type]) def get_field_type_from_lookup( diff --git a/tests/typecheck/managers/querysets/test_from_queryset.yml b/tests/typecheck/managers/querysets/test_from_queryset.yml index 2cfbe2aff..7a173d77d 100644 --- a/tests/typecheck/managers/querysets/test_from_queryset.yml +++ b/tests/typecheck/managers/querysets/test_from_queryset.yml @@ -43,6 +43,31 @@ class MyModelWithoutSelf(models.Model): objects = ManagerWithoutSelf() +- case: from_queryset_model_inheritance + main: | + from myapp.models import Base, Sub + reveal_type(Base.objects) # N: Revealed type is "myapp.models.MyManager[myapp.models.Base]" + reveal_type(Sub.objects) # N: Revealed type is "myapp.models.MyManager[myapp.models.Sub]" + installed_apps: + - myapp + files: + - path: myapp/__init__.py + - path: myapp/models.py + content: | + from typing import ClassVar + from typing_extensions import Self + from django.db.models import Model + from django.db.models.manager import BaseManager + from django.db.models.query import QuerySet + + MyManager = BaseManager.from_queryset(QuerySet, "MyManager") + + class Base(Model): + objects: ClassVar[MyManager[Self]] = MyManager() + + class Sub(Base): + pass + - case: from_queryset_with_base_manager main: | from myapp.models import MyModel diff --git a/tests/typecheck/managers/test_managers.yml b/tests/typecheck/managers/test_managers.yml index 89041f648..1769c0cdf 100644 --- a/tests/typecheck/managers/test_managers.yml +++ b/tests/typecheck/managers/test_managers.yml @@ -583,6 +583,7 @@ - path: myapp/models.py content: | from typing import ClassVar, TypeVar + from typing_extensions import Self from django.db import models T = TypeVar("T", bound="MyModel") @@ -597,7 +598,7 @@ pass class MySubModel(MyModel): - objects: ClassVar[MySubManager["MySubModel"]] = MySubManager() + objects: ClassVar[MySubManager[Self]] = MySubManager() - case: subclass_manager_without_type_parameters_disallow_any_generics main: |