Opened 8 hours ago

Last modified 32 minutes ago

#36239 new Bug

ManyToManyField check error with invalid "to" when passing through/through_fields

Reported by: Jordan Hyatt Owned by:
Component: Core (System checks) Version: 5.1
Severity: Normal Keywords: check
Cc: Jordan Hyatt Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

Bug was discussed in the forums hereā€‹https://forum.djangoproject.com/t/manytomanyfield-error-message-with-incorrect-to-argument/39394.

Basically, if an invalid "to" argument is passed to ManyToManyField while also passing the through/through_fields arguments the check framework crashes giving unhelpful error message/traceback.

Minimal reproduceable example:

class Foo(Model):
    pass

class Bar(Model):
    foos = ManyToManyField(
        to = "Fo", # NOTE incorrect "to" argument
        through = 'FooBar',
        through_fields = ('bar', 'foo')
    )

class FooBar(Model):
    foo = ForeignKey('Foo', on_delete=CASCADE)
    bar = ForeignKey('Bar', on_delete=CASCADE)

Traceback:

File "django/core/checks/registry.py", line 88, in run_checks
    new_errors = check(app_configs=app_configs, databases=databases)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "django/core/checks/model_checks.py", line 36, in check_all_models
    errors.extend(model.check(**kwargs))
                  ^^^^^^^^^^^^^^^^^^^^^
  File "django/db/models/base.py", line 1691, in check
    *cls._check_fields(**kwargs),
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "django/db/models/base.py", line 1828, in _check_fields
    errors.extend(field.check(from_model=cls, **kwargs))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "django/db/models/fields/related.py", line 1400, in check
    *self._check_relationship_model(**kwargs),
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "django/db/models/fields/related.py", line 1676, in _check_relationship_model
    related_model._meta.object_name,
    ^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute '_meta'

Proposed Patch:

diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
index 6a9cb12a90..dd4c09a4e3 100644
--- a/django/db/models/fields/related.py
+++ b/django/db/models/fields/related.py
@@ -1707,13 +1707,18 @@ def _check_relationship_model(self, from_model=None, **kwargs):
                             and getattr(field.remote_field, "model", None)
                             == related_model
                         ):
+                            related_object_name = (
+                                related_model
+                                if isinstance(related_model, str)
+                                else related_model._meta.object_name
+                            )
                             errors.append(
                                 checks.Error(
                                     "'%s.%s' is not a foreign key to '%s'."
                                     % (
                                         through._meta.object_name,
                                         field_name,
-                                        related_model._meta.object_name,
+                                        related_object_name,
                                     ),
                                     hint=hint,
                                     obj=self,

Change History (1)

comment:1 by Amaan-ali03, 32 minutes ago

Hey Django Team,
Iā€™d love to work on this issue!
Requesting to assign this ticket to @Amaan-ali03 to implement the proposed fix for the ManyToManyField error with an invalid "to" argument.

Proposed Approach:

Identify the Issue: The bug occurs when an invalid "to" argument is passed to ManyToManyField along with through and through_fields, causing an AttributeError due to improper handling of the related_model variable.
Proposed Solution: Update the _check_relationship_model method in django/db/models/fields/related.py to include a type check for related_model. Instead of directly accessing related_model._meta, the code should verify if related_model is a string and handle it accordingly to avoid the crash.

Note: See TracTickets for help on using tickets.
Back to Top