Skip to content

Commit

Permalink
fix .values_list returns incorrect type for field with same name when…
Browse files Browse the repository at this point in the history
… selected from related model (#2431)

Co-authored-by: Niicck <[email protected]>
  • Loading branch information
Niicck and Niicck authored Nov 4, 2024
1 parent fffaa27 commit a7e3728
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*.egg-info
.DS_Store
.idea/
.vscode/
.mypy_cache/
.pytest_cache/
.ruff_cache/
Expand Down
10 changes: 5 additions & 5 deletions mypy_django_plugin/django/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ def get_field_related_model_cls(self, field: Union["RelatedField[Any, Any]", For

def _resolve_field_from_parts(
self, field_parts: Iterable[str], model_cls: Type[Model]
) -> Union["Field[Any, Any]", ForeignObjectRel]:
) -> Tuple[Union["Field[Any, Any]", ForeignObjectRel], Type[Model]]:
currently_observed_model = model_cls
field: Union[Field[Any, Any], ForeignObjectRel, GenericForeignKey, None] = None
for field_part in field_parts:
Expand All @@ -429,7 +429,7 @@ def _resolve_field_from_parts(

# Guaranteed by `query.solve_lookup_type` before.
assert isinstance(field, (Field, ForeignObjectRel))
return field
return field, currently_observed_model

def solve_lookup_type(
self, model_cls: Type[Model], lookup: str
Expand Down Expand Up @@ -467,10 +467,10 @@ def solve_lookup_type(

def resolve_lookup_into_field(
self, model_cls: Type[Model], lookup: str
) -> Union["Field[Any, Any]", ForeignObjectRel, None]:
) -> Tuple[Union["Field[Any, Any]", ForeignObjectRel, None], Type[Model]]:
solved_lookup = self.solve_lookup_type(model_cls, lookup)
if solved_lookup is None:
return None
return None, model_cls
lookup_parts, field_parts, is_expression = solved_lookup
if lookup_parts:
raise LookupsAreUnsupported()
Expand Down Expand Up @@ -501,7 +501,7 @@ def resolve_lookup_expected_type(
if is_expression:
return AnyType(TypeOfAny.explicit)

field = self._resolve_field_from_parts(field_parts, model_cls)
field, _ = self._resolve_field_from_parts(field_parts, model_cls)

lookup_cls = None
if lookup_parts:
Expand Down
2 changes: 1 addition & 1 deletion mypy_django_plugin/transformers/querysets.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def get_field_type_from_lookup(
silent_on_error: bool = False,
) -> Optional[MypyType]:
try:
lookup_field = django_context.resolve_lookup_into_field(model_cls, lookup)
lookup_field, model_cls = django_context.resolve_lookup_into_field(model_cls, lookup)
except FieldError as exc:
if not silent_on_error:
ctx.api.fail(exc.args[0], ctx.context)
Expand Down
18 changes: 18 additions & 0 deletions tests/typecheck/managers/querysets/test_values_list.yml
Original file line number Diff line number Diff line change
Expand Up @@ -322,3 +322,21 @@
class Blog(models.Model):
num_posts = models.IntegerField()
text = models.CharField(max_length=100, blank=True)
- case: handles_field_with_same_name_on_other_model
main: |
from myapp.models import A
reveal_type(A.objects.values_list("name", "b__name").get()) # N: Revealed type is "Tuple[builtins.int, builtins.str]"
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models.py
content: |
from django.db import models
class B(models.Model):
name = models.CharField()
class A(models.Model):
b = models.ForeignKey(B, on_delete=models.CASCADE)
name = models.IntegerField()

0 comments on commit a7e3728

Please sign in to comment.