Skip to content

Commit

Permalink
Fix ForeignKey queryset filters for cases where the to argument is a …
Browse files Browse the repository at this point in the history
…string like 'app_label.model_name'.
  • Loading branch information
Kircheneer committed Apr 13, 2023
1 parent be609f1 commit e9925e4
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 2 deletions.
22 changes: 20 additions & 2 deletions mypy_django_plugin/django/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from contextlib import contextmanager
from typing import TYPE_CHECKING, Any, Dict, Iterable, Iterator, Optional, Sequence, Set, Tuple, Type, Union

from django.core.exceptions import FieldError
from django.core.exceptions import FieldError, FieldDoesNotExist
from django.db import models
from django.db.models.base import Model
from django.db.models.expressions import Expression
Expand Down Expand Up @@ -385,7 +385,25 @@ def solve_lookup_type(
# Primary key lookup when no primary key field is found, model is presumably
# abstract and we can't say anything about 'pk'.
return None
return query.solve_lookup_type(lookup)
try:
return query.solve_lookup_type(lookup)
# This occurs when the following conditions are met:
# - model_cls._meta.abstract = True
# - part of the lookup is a foreign key defined on model_cls where the 'to' argument is a string
# On abstract models the 'to' parameter is only coalesced into the actual class whenever a subclass of it is
# instantiated, therefore it is never swapped out for abstract base classes.
except AttributeError:
pass
query_parts = lookup.split("__")
try:
field = query.get_meta().get_field(query_parts[0])
if len(query_parts) == 1:
return [], [query_parts[0]], False
sub_query = Query(field.related_model).solve_lookup_type("__")
entire_query_parts = [query_parts[0], *sub_query[1]]
return sub_query[0], entire_query_parts, sub_query[2]
except FieldDoesNotExist:
return None

def resolve_lookup_into_field(
self, model_cls: Type[Model], lookup: str
Expand Down
26 changes: 26 additions & 0 deletions tests/typecheck/fields/test_related.yml
Original file line number Diff line number Diff line change
Expand Up @@ -943,3 +943,29 @@
non_installed = models.ForeignKey( # E: Cannot find model 'not_installed.NonInstalledModel' referenced in field 'non_installed'
"not_installed.NonInstalledModel", on_delete=models.CASCADE
)
- case: test_foreign_key_to_as_string
main: |
from myapp.models import Book, Publisher
publisher = Publisher.objects.create(name="Example Publisher")
book = Book.objects.create(name="Book", publisher=publisher)
Book.objects.filter(publisher=publisher)
installed_apps:
- myapp
files:
- path: myapp/__init__.py
- path: myapp/models/__init__.py
content: |
from django.db import models
from django.db.models.query import QuerySet
class Publisher(models.Model):
name = models.CharField()
class PrintedGood(models.Model):
publisher = models.ForeignKey(to="myapp.Publisher", on_delete=models.CASCADE)
class Meta:
abstract = True
class Book(PrintedGood):
name = models.CharField()

0 comments on commit e9925e4

Please sign in to comment.