Fixed #32294 -- Prevented ManyToManyField's hidden related name collisions between apps.

This commit is contained in:
manav014 2020-12-30 07:52:17 +05:30 committed by Mariusz Felisiak
parent 74fd233b14
commit a9a7421ab8
4 changed files with 44 additions and 14 deletions

View File

@ -1614,7 +1614,11 @@ class ManyToManyField(RelatedField):
# related_name with one generated from the m2m field name. Django
# still uses backwards relations internally and we need to avoid
# clashes between multiple m2m fields with related_name == '+'.
self.remote_field.related_name = "_%s_%s_+" % (cls.__name__.lower(), name)
self.remote_field.related_name = '_%s_%s_%s_+' % (
cls._meta.app_label,
cls.__name__.lower(),
name,
)
super().contribute_to_class(cls, name, **kwargs)

View File

@ -3,7 +3,7 @@ from unittest import mock
from django.core.checks import Error, Warning as DjangoWarning
from django.db import connection, models
from django.test.testcases import SimpleTestCase
from django.test.utils import isolate_apps, override_settings
from django.test.utils import isolate_apps, modify_settings, override_settings
@isolate_apps('invalid_models_tests')
@ -1025,6 +1025,32 @@ class ReverseQueryNameClashTests(SimpleTestCase):
),
])
@modify_settings(INSTALLED_APPS={'append': 'basic'})
@isolate_apps('basic', 'invalid_models_tests')
def test_no_clash_across_apps_without_accessor(self):
class Target(models.Model):
class Meta:
app_label = 'invalid_models_tests'
class Model(models.Model):
m2m = models.ManyToManyField(Target, related_name='+')
class Meta:
app_label = 'basic'
def _test():
# Define model with the same name.
class Model(models.Model):
m2m = models.ManyToManyField(Target, related_name='+')
class Meta:
app_label = 'invalid_models_tests'
self.assertEqual(Model.check(), [])
_test()
self.assertEqual(Model.check(), [])
@isolate_apps('invalid_models_tests')
class ExplicitRelatedNameClashTests(SimpleTestCase):

View File

@ -321,7 +321,7 @@ TEST_RESULTS = {
'get_all_related_objects_with_model_hidden_local': {
Person: (
('+', None),
('_relating_people_hidden_+', None),
('_model_meta_relating_people_hidden_+', None),
('Person_following_inherited+', None),
('Person_following_inherited+', None),
('Person_friends_inherited+', None),
@ -339,7 +339,7 @@ TEST_RESULTS = {
),
ProxyPerson: (
('+', Person),
('_relating_people_hidden_+', Person),
('_model_meta_relating_people_hidden_+', Person),
('Person_following_inherited+', Person),
('Person_following_inherited+', Person),
('Person_friends_inherited+', Person),
@ -357,7 +357,7 @@ TEST_RESULTS = {
),
BasePerson: (
('+', None),
('_relating_basepeople_hidden_+', None),
('_model_meta_relating_basepeople_hidden_+', None),
('BasePerson_following_abstract+', None),
('BasePerson_following_abstract+', None),
('BasePerson_following_base+', None),
@ -408,8 +408,8 @@ TEST_RESULTS = {
Person: (
('+', BasePerson),
('+', None),
('_relating_basepeople_hidden_+', BasePerson),
('_relating_people_hidden_+', None),
('_model_meta_relating_basepeople_hidden_+', BasePerson),
('_model_meta_relating_people_hidden_+', None),
('BasePerson_following_abstract+', BasePerson),
('BasePerson_following_abstract+', BasePerson),
('BasePerson_following_base+', BasePerson),
@ -446,8 +446,8 @@ TEST_RESULTS = {
ProxyPerson: (
('+', BasePerson),
('+', Person),
('_relating_basepeople_hidden_+', BasePerson),
('_relating_people_hidden_+', Person),
('_model_meta_relating_basepeople_hidden_+', BasePerson),
('_model_meta_relating_people_hidden_+', Person),
('BasePerson_following_abstract+', BasePerson),
('BasePerson_following_abstract+', BasePerson),
('BasePerson_following_base+', BasePerson),
@ -483,7 +483,7 @@ TEST_RESULTS = {
),
BasePerson: (
('+', None),
('_relating_basepeople_hidden_+', None),
('_model_meta_relating_basepeople_hidden_+', None),
('BasePerson_following_abstract+', None),
('BasePerson_following_abstract+', None),
('BasePerson_following_base+', None),
@ -822,7 +822,7 @@ TEST_RESULTS = {
('friends_base_rel_+', None),
('followers_base', None),
('relating_basepeople', None),
('_relating_basepeople_hidden_+', None),
('_model_meta_relating_basepeople_hidden_+', None),
),
Person: (
('friends_abstract_rel_+', BasePerson),
@ -830,7 +830,7 @@ TEST_RESULTS = {
('friends_base_rel_+', BasePerson),
('followers_base', BasePerson),
('relating_basepeople', BasePerson),
('_relating_basepeople_hidden_+', BasePerson),
('_model_meta_relating_basepeople_hidden_+', BasePerson),
('friends_inherited_rel_+', None),
('followers_concrete', None),
('relating_people', None),
@ -849,7 +849,7 @@ TEST_RESULTS = {
'friends_base_rel_+',
'followers_base',
'relating_basepeople',
'_relating_basepeople_hidden_+',
'_model_meta_relating_basepeople_hidden_+',
],
Person: [
'friends_inherited_rel_+',

View File

@ -257,7 +257,7 @@ class RelationTreeTests(SimpleTestCase):
self.assertEqual(
sorted(field.related_query_name() for field in BasePerson._meta._relation_tree),
sorted([
'+', '_relating_basepeople_hidden_+', 'BasePerson_following_abstract+',
'+', '_model_meta_relating_basepeople_hidden_+', 'BasePerson_following_abstract+',
'BasePerson_following_abstract+', 'BasePerson_following_base+', 'BasePerson_following_base+',
'BasePerson_friends_abstract+', 'BasePerson_friends_abstract+', 'BasePerson_friends_base+',
'BasePerson_friends_base+', 'BasePerson_m2m_abstract+', 'BasePerson_m2m_base+', 'Relating_basepeople+',