mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Fixed #22977 -- Added check for clash between model manager and model field's related_name
.
New check added on model related fields to check if the `related_name` conflicts with the respective model's manager name. With thanks to kswiat, loic, felixxm and russellm
This commit is contained in:
parent
1860a1afc9
commit
0cb31fda4e
@ -581,6 +581,7 @@ class ForeignObject(RelatedField):
|
|||||||
*super().check(**kwargs),
|
*super().check(**kwargs),
|
||||||
*self._check_to_fields_exist(),
|
*self._check_to_fields_exist(),
|
||||||
*self._check_unique_target(),
|
*self._check_unique_target(),
|
||||||
|
*self._check_conflict_with_managers(),
|
||||||
]
|
]
|
||||||
|
|
||||||
def _check_to_fields_exist(self):
|
def _check_to_fields_exist(self):
|
||||||
@ -679,6 +680,28 @@ class ForeignObject(RelatedField):
|
|||||||
]
|
]
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def _check_conflict_with_managers(self):
|
||||||
|
errors = []
|
||||||
|
for manager in self.opts.managers:
|
||||||
|
for rel_objs in self.model._meta.related_objects:
|
||||||
|
manager_name = manager.name
|
||||||
|
related_object_name = rel_objs.name
|
||||||
|
if manager_name == related_object_name:
|
||||||
|
field_name = f"{self.model._meta.object_name}.{self.name}"
|
||||||
|
errors.append(
|
||||||
|
checks.Error(
|
||||||
|
f"Related name for '{field_name}' clashes with "
|
||||||
|
f"manager: '{related_object_name}' name.",
|
||||||
|
hint=(
|
||||||
|
"Rename manager name or related_name "
|
||||||
|
"in conflicted field"
|
||||||
|
),
|
||||||
|
obj=self,
|
||||||
|
id="fields.E341",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return errors
|
||||||
|
|
||||||
def deconstruct(self):
|
def deconstruct(self):
|
||||||
name, path, args, kwargs = super().deconstruct()
|
name, path, args, kwargs = super().deconstruct()
|
||||||
kwargs["on_delete"] = self.remote_field.on_delete
|
kwargs["on_delete"] = self.remote_field.on_delete
|
||||||
|
@ -327,6 +327,8 @@ Related fields
|
|||||||
* **fields.E339**: ``<model>.<field name>`` is not a foreign key to ``<model>``.
|
* **fields.E339**: ``<model>.<field name>`` is not a foreign key to ``<model>``.
|
||||||
* **fields.E340**: The field's intermediary table ``<table name>`` clashes with
|
* **fields.E340**: The field's intermediary table ``<table name>`` clashes with
|
||||||
the table name of ``<model>``/``<model>.<field name>``.
|
the table name of ``<model>``/``<model>.<field name>``.
|
||||||
|
* **fields.E341**: ``<model>``.``related_name`` must be different than the
|
||||||
|
``<model>``'s manager name.
|
||||||
* **fields.W340**: ``null`` has no effect on ``ManyToManyField``.
|
* **fields.W340**: ``null`` has no effect on ``ManyToManyField``.
|
||||||
* **fields.W341**: ``ManyToManyField`` does not support ``validators``.
|
* **fields.W341**: ``ManyToManyField`` does not support ``validators``.
|
||||||
* **fields.W342**: Setting ``unique=True`` on a ``ForeignKey`` has the same
|
* **fields.W342**: Setting ``unique=True`` on a ``ForeignKey`` has the same
|
||||||
|
@ -1407,6 +1407,29 @@ class ExplicitRelatedQueryNameClashTests(SimpleTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@isolate_apps("invalid_models_tests")
|
||||||
|
class RelatedQueryNameClashWithManagerTests(SimpleTestCase):
|
||||||
|
def test_clash_between_related_query_name_and_manager(self):
|
||||||
|
class Author(models.Model):
|
||||||
|
authors = models.Manager()
|
||||||
|
mentor = models.ForeignKey(
|
||||||
|
"self", related_name="authors", on_delete=models.CASCADE
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
Author.check(),
|
||||||
|
[
|
||||||
|
Error(
|
||||||
|
"Related name for 'Author.mentor' clashes with manager: "
|
||||||
|
"'authors' name.",
|
||||||
|
hint="Rename manager name or related_name in conflicted field",
|
||||||
|
obj=Author._meta.get_field("mentor"),
|
||||||
|
id="fields.E341",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@isolate_apps("invalid_models_tests")
|
@isolate_apps("invalid_models_tests")
|
||||||
class SelfReferentialM2MClashTests(SimpleTestCase):
|
class SelfReferentialM2MClashTests(SimpleTestCase):
|
||||||
def test_clash_between_accessors(self):
|
def test_clash_between_accessors(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user