Skip to content

Commit

Permalink
Handle possible unregistered models
Browse files Browse the repository at this point in the history
  • Loading branch information
UnknownPlatypus committed May 24, 2023
1 parent 228e285 commit 1290dc5
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 4 deletions.
27 changes: 23 additions & 4 deletions mypy_django_plugin/django/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ def get_field_lookup_exact_type(
) -> MypyType:
if isinstance(field, (RelatedField, ForeignObjectRel)):
related_model_cls = self.get_field_related_model_cls(field)
if related_model_cls is None:
return AnyType(TypeOfAny.from_error)
primary_key_field = self.get_primary_key_field(related_model_cls)
primary_key_type = self.get_field_get_type(api, primary_key_field, method="init")

Expand Down Expand Up @@ -354,7 +356,7 @@ def get_field_related_model_cls(

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

field = currently_observed_model._meta.get_field(field_part)
if isinstance(field, RelatedField):
currently_observed_model = self.get_field_related_model_cls(field)
related_model = self.get_field_related_model_cls(field)
if related_model is None:
return None
currently_observed_model = related_model
model_name = currently_observed_model._meta.model_name
if model_name is not None and field_part == (model_name + "_id"):
field = self.get_primary_key_field(currently_observed_model)

if isinstance(field, ForeignObjectRel):
currently_observed_model = self.get_field_related_model_cls(field)
related_model = self.get_field_related_model_cls(field)
if related_model is None:
return None
currently_observed_model = related_model

# Guaranteed by `query.solve_lookup_type` before.
assert isinstance(field, (Field, ForeignObjectRel))
Expand Down Expand Up @@ -398,9 +406,18 @@ def solve_lookup_type(
field = query.get_meta().get_field(query_parts[0])
except FieldDoesNotExist:
return None

if len(query_parts) == 1:
return [], [query_parts[0]], False
sub_query = Query(field.related_model).solve_lookup_type("__")

related_model = None
if isinstance(field, (RelatedField, ForeignObjectRel)):
related_model = self.get_field_related_model_cls(field)

if related_model is None:
return None

sub_query = Query(related_model).solve_lookup_type("__".join(query_parts[1:]))
entire_query_parts = [query_parts[0], *sub_query[1]]
return sub_query[0], entire_query_parts, sub_query[2]

Expand Down Expand Up @@ -429,6 +446,8 @@ def resolve_lookup_expected_type(self, ctx: MethodContext, model_cls: Type[Model
return AnyType(TypeOfAny.explicit)

field = self._resolve_field_from_parts(field_parts, model_cls)
if field is None:
return AnyType(TypeOfAny.from_error)

lookup_cls = None
if lookup_parts:
Expand Down
1 change: 1 addition & 0 deletions tests/typecheck/fields/test_related.yml
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,7 @@
- case: test_fails_if_app_label_is_unknown_in_relation_field
main: |
from installed.models import InstalledModel
InstalledModel.objects.filter(non_installed__isnull=True)
installed_apps:
- installed
files:
Expand Down

0 comments on commit 1290dc5

Please sign in to comment.