From 5d4f21b16f002ed5202a68d6977346ccf53b0b0e Mon Sep 17 00:00:00 2001 From: Nick Touran Date: Wed, 4 Aug 2021 13:19:29 -0700 Subject: [PATCH] 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 --- django/db/models/fields/related.py | 10 ++++++++++ docs/ref/checks.txt | 2 ++ tests/invalid_models_tests/test_relative_fields.py | 14 ++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index febaadbb5b..c5157dc1fb 100644 --- a/django/db/models/fields/related.py +++ b/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): diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt index 3147114f8d..2ea2fd0df2 100644 --- a/docs/ref/checks.txt +++ b/docs/ref/checks.txt @@ -313,6 +313,8 @@ Related fields with a ``through`` model. * **fields.W344**: The field's intermediary table ```` clashes with the table name of ````/``.``. +* **fields.W345**: ``related_name`` has no effect on ``ManyToManyField`` with a + symmetrical relationship, e.g. to "self". Models ------ diff --git a/tests/invalid_models_tests/test_relative_fields.py b/tests/invalid_models_tests/test_relative_fields.py index 8909b12214..6fef14c335 100644 --- a/tests/invalid_models_tests/test_relative_fields.py +++ b/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