|
3 | 3 |
|
4 | 4 | from django.core.exceptions import FieldError |
5 | 5 | from django.db.models.base import Model |
| 6 | +from django.db.models.fields.related import RelatedField |
6 | 7 | from mypy.newsemanal.typeanal import TypeAnalyser |
7 | 8 | from mypy.nodes import Expression, NameExpr, TypeInfo |
8 | 9 | from mypy.plugin import AnalyzeTypeContext, FunctionContext, MethodContext |
9 | 10 | from mypy.types import AnyType, Instance |
10 | 11 | from mypy.types import Type as MypyType |
11 | 12 | from mypy.types import TypeOfAny |
12 | 13 |
|
13 | | -from django.db.models.fields.related import RelatedField |
14 | 14 | from mypy_django_plugin.django.context import DjangoContext |
15 | 15 | from mypy_django_plugin.lib import fullnames, helpers |
16 | 16 |
|
17 | 17 |
|
| 18 | +def _extract_model_type_from_queryset(queryset_type: Instance) -> Optional[Instance]: |
| 19 | + for base_type in [queryset_type, *queryset_type.type.bases]: |
| 20 | + if (len(base_type.args) |
| 21 | + and isinstance(base_type.args[0], Instance) |
| 22 | + and base_type.args[0].type.has_base(fullnames.MODEL_CLASS_FULLNAME)): |
| 23 | + return base_type.args[0] |
| 24 | + return None |
| 25 | + |
| 26 | + |
18 | 27 | def determine_proper_manager_type(ctx: FunctionContext) -> MypyType: |
19 | 28 | default_return_type = ctx.default_return_type |
20 | 29 | assert isinstance(default_return_type, Instance) |
@@ -98,11 +107,10 @@ def extract_proper_type_queryset_values_list(ctx: MethodContext, django_context: |
98 | 107 | assert isinstance(ctx.type, Instance) |
99 | 108 | assert isinstance(ctx.default_return_type, Instance) |
100 | 109 |
|
101 | | - # bail if queryset of Any or other non-instances |
102 | | - if not isinstance(ctx.type.args[0], Instance): |
| 110 | + model_type = _extract_model_type_from_queryset(ctx.type) |
| 111 | + if model_type is None: |
103 | 112 | return AnyType(TypeOfAny.from_omitted_generics) |
104 | 113 |
|
105 | | - model_type = ctx.type.args[0] |
106 | 114 | model_cls = django_context.get_model_class_by_fullname(model_type.type.fullname()) |
107 | 115 | if model_cls is None: |
108 | 116 | return ctx.default_return_type |
@@ -148,11 +156,10 @@ def extract_proper_type_queryset_values(ctx: MethodContext, django_context: Djan |
148 | 156 | assert isinstance(ctx.type, Instance) |
149 | 157 | assert isinstance(ctx.default_return_type, Instance) |
150 | 158 |
|
151 | | - # if queryset of non-instance type |
152 | | - if not isinstance(ctx.type.args[0], Instance): |
| 159 | + model_type = _extract_model_type_from_queryset(ctx.type) |
| 160 | + if model_type is None: |
153 | 161 | return AnyType(TypeOfAny.from_omitted_generics) |
154 | 162 |
|
155 | | - model_type = ctx.type.args[0] |
156 | 163 | model_cls = django_context.get_model_class_by_fullname(model_type.type.fullname()) |
157 | 164 | if model_cls is None: |
158 | 165 | return ctx.default_return_type |
|
0 commit comments