Skip to content

Commit d6010fd

Browse files
authored
Check calls to filtering manager methods involving ManyToManyField (#2275)
1 parent d747285 commit d6010fd

File tree

3 files changed

+28
-1
lines changed

3 files changed

+28
-1
lines changed

mypy_django_plugin/django/context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def __init__(self, django_settings_module: str) -> None:
132132
def model_modules(self) -> Dict[str, Dict[str, Type[Model]]]:
133133
"""All modules that contain Django models."""
134134
modules: Dict[str, Dict[str, Type[Model]]] = defaultdict(dict)
135-
for concrete_model_cls in self.apps_registry.get_models():
135+
for concrete_model_cls in self.apps_registry.get_models(include_auto_created=True, include_swapped=True):
136136
modules[concrete_model_cls.__module__][concrete_model_cls.__name__] = concrete_model_cls
137137
# collect abstract=True models
138138
for model_cls in concrete_model_cls.mro()[1:]:

mypy_django_plugin/transformers/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,7 @@ def create_many_related_manager(self, model: Instance) -> None:
932932
helpers.set_many_to_many_manager_info(
933933
to=model.type, derived_from="_default_manager", manager_info=related_manager_info
934934
)
935+
helpers.add_new_manager_base(self.api, related_manager_info.fullname)
935936

936937

937938
class MetaclassAdjustments(ModelClassInitializer):

tests/typecheck/fields/test_related.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,3 +1472,29 @@
14721472
14731473
class Second(Parent):
14741474
...
1475+
1476+
- case: test_m2m_models_manager_filter_kwargs_checked
1477+
main: |
1478+
from myapp.models import MyModel, Other
1479+
MyModel.objects.filter(xyz__isnull=False) # E: Cannot resolve keyword 'xyz' into field. Choices are: id, others [misc]
1480+
MyModel.objects.get(xyz__isnull=False) # E: Cannot resolve keyword 'xyz' into field. Choices are: id, others [misc]
1481+
MyModel.objects.exclude(xyz__isnull=False) # E: Cannot resolve keyword 'xyz' into field. Choices are: id, others [misc]
1482+
other = Other()
1483+
other.mymodel_set.filter(xyz__isnull=True) # E: Cannot resolve keyword 'xyz' into field. Choices are: id, mymodel, mymodel_id, other, other_id [misc]
1484+
other.mymodel_set.get(xyz__isnull=True) # E: Cannot resolve keyword 'xyz' into field. Choices are: id, mymodel, mymodel_id, other, other_id [misc]
1485+
other.mymodel_set.exclude(xyz__isnull=True) # E: Cannot resolve keyword 'xyz' into field. Choices are: id, mymodel, mymodel_id, other, other_id [misc]
1486+
MyModel.others.through.objects.filter(xyz__isnull=False) # E: Cannot resolve keyword 'xyz' into field. Choices are: id, mymodel, mymodel_id, other, other_id [misc]
1487+
MyModel.others.through.objects.get(xyz__isnull=False) # E: Cannot resolve keyword 'xyz' into field. Choices are: id, mymodel, mymodel_id, other, other_id [misc]
1488+
MyModel.others.through.objects.exclude(xyz__isnull=False) # E: Cannot resolve keyword 'xyz' into field. Choices are: id, mymodel, mymodel_id, other, other_id [misc]
1489+
installed_apps:
1490+
- myapp
1491+
files:
1492+
- path: myapp/__init__.py
1493+
- path: myapp/models.py
1494+
content: |
1495+
from django.db import models
1496+
class Other(models.Model):
1497+
...
1498+
1499+
class MyModel(models.Model):
1500+
others = models.ManyToManyField(Other)

0 commit comments

Comments
 (0)