2
0
Эх сурвалжийг харах

Fixed #32983 -- Added system check for redundant related_name on symmetrical M2M fields.

Since ManyToManyFields defined with `symmetrical=True` do not add a
related field to the target model, including a `related_name` argument
will never do what the coder likely expects. This makes including
a related_name with a symmetrical model raise a system check warning.

ticket-32983
Nick Touran 3 жил өмнө
parent
commit
5d4f21b16f

+ 10 - 0
django/db/models/fields/related.py

@@ -1258,6 +1258,16 @@ class ManyToManyField(RelatedField):
                 )
             )
 
+        if self.remote_field.symmetrical and self._related_name:
+            warnings.append(
+                checks.Warning(
+                    'related_name has no effect on ManyToManyField '
+                    'with a symmetrical relationship, e.g. to "self".',
+                    obj=self,
+                    id='fields.W345',
+                )
+            )
+
         return warnings
 
     def _check_relationship_model(self, from_model=None, **kwargs):

+ 2 - 0
docs/ref/checks.txt

@@ -313,6 +313,8 @@ Related fields
   with a ``through`` model.
 * **fields.W344**: The field's intermediary table ``<table name>`` clashes with
   the table name of ``<model>``/``<model>.<field name>``.
+* **fields.W345**: ``related_name`` has no effect on ``ManyToManyField`` with a
+  symmetrical relationship, e.g. to "self".
 
 Models
 ------

+ 14 - 0
tests/invalid_models_tests/test_relative_fields.py

@@ -128,6 +128,20 @@ class RelativeFieldTests(SimpleTestCase):
             ),
         ])
 
+    def test_many_to_many_with_useless_related_name(self):
+        class ModelM2M(models.Model):
+            m2m = models.ManyToManyField('self', related_name='children')
+
+        field = ModelM2M._meta.get_field('m2m')
+        self.assertEqual(ModelM2M.check(), [
+            DjangoWarning(
+                'related_name has no effect on ManyToManyField with '
+                'a symmetrical relationship, e.g. to "self".',
+                obj=field,
+                id='fields.W345',
+            ),
+        ])
+
     def test_ambiguous_relationship_model_from(self):
         class Person(models.Model):
             pass