Fixed #32294 -- Prevented ManyToManyField's hidden related name collisions between apps.
This commit is contained in:
parent
74fd233b14
commit
a9a7421ab8
|
@ -1614,7 +1614,11 @@ class ManyToManyField(RelatedField):
|
||||||
# related_name with one generated from the m2m field name. Django
|
# related_name with one generated from the m2m field name. Django
|
||||||
# still uses backwards relations internally and we need to avoid
|
# still uses backwards relations internally and we need to avoid
|
||||||
# clashes between multiple m2m fields with related_name == '+'.
|
# 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)
|
super().contribute_to_class(cls, name, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ from unittest import mock
|
||||||
from django.core.checks import Error, Warning as DjangoWarning
|
from django.core.checks import Error, Warning as DjangoWarning
|
||||||
from django.db import connection, models
|
from django.db import connection, models
|
||||||
from django.test.testcases import SimpleTestCase
|
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')
|
@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')
|
@isolate_apps('invalid_models_tests')
|
||||||
class ExplicitRelatedNameClashTests(SimpleTestCase):
|
class ExplicitRelatedNameClashTests(SimpleTestCase):
|
||||||
|
|
|
@ -321,7 +321,7 @@ TEST_RESULTS = {
|
||||||
'get_all_related_objects_with_model_hidden_local': {
|
'get_all_related_objects_with_model_hidden_local': {
|
||||||
Person: (
|
Person: (
|
||||||
('+', None),
|
('+', None),
|
||||||
('_relating_people_hidden_+', None),
|
('_model_meta_relating_people_hidden_+', None),
|
||||||
('Person_following_inherited+', None),
|
('Person_following_inherited+', None),
|
||||||
('Person_following_inherited+', None),
|
('Person_following_inherited+', None),
|
||||||
('Person_friends_inherited+', None),
|
('Person_friends_inherited+', None),
|
||||||
|
@ -339,7 +339,7 @@ TEST_RESULTS = {
|
||||||
),
|
),
|
||||||
ProxyPerson: (
|
ProxyPerson: (
|
||||||
('+', Person),
|
('+', Person),
|
||||||
('_relating_people_hidden_+', Person),
|
('_model_meta_relating_people_hidden_+', Person),
|
||||||
('Person_following_inherited+', Person),
|
('Person_following_inherited+', Person),
|
||||||
('Person_following_inherited+', Person),
|
('Person_following_inherited+', Person),
|
||||||
('Person_friends_inherited+', Person),
|
('Person_friends_inherited+', Person),
|
||||||
|
@ -357,7 +357,7 @@ TEST_RESULTS = {
|
||||||
),
|
),
|
||||||
BasePerson: (
|
BasePerson: (
|
||||||
('+', None),
|
('+', None),
|
||||||
('_relating_basepeople_hidden_+', None),
|
('_model_meta_relating_basepeople_hidden_+', None),
|
||||||
('BasePerson_following_abstract+', None),
|
('BasePerson_following_abstract+', None),
|
||||||
('BasePerson_following_abstract+', None),
|
('BasePerson_following_abstract+', None),
|
||||||
('BasePerson_following_base+', None),
|
('BasePerson_following_base+', None),
|
||||||
|
@ -408,8 +408,8 @@ TEST_RESULTS = {
|
||||||
Person: (
|
Person: (
|
||||||
('+', BasePerson),
|
('+', BasePerson),
|
||||||
('+', None),
|
('+', None),
|
||||||
('_relating_basepeople_hidden_+', BasePerson),
|
('_model_meta_relating_basepeople_hidden_+', BasePerson),
|
||||||
('_relating_people_hidden_+', None),
|
('_model_meta_relating_people_hidden_+', None),
|
||||||
('BasePerson_following_abstract+', BasePerson),
|
('BasePerson_following_abstract+', BasePerson),
|
||||||
('BasePerson_following_abstract+', BasePerson),
|
('BasePerson_following_abstract+', BasePerson),
|
||||||
('BasePerson_following_base+', BasePerson),
|
('BasePerson_following_base+', BasePerson),
|
||||||
|
@ -446,8 +446,8 @@ TEST_RESULTS = {
|
||||||
ProxyPerson: (
|
ProxyPerson: (
|
||||||
('+', BasePerson),
|
('+', BasePerson),
|
||||||
('+', Person),
|
('+', Person),
|
||||||
('_relating_basepeople_hidden_+', BasePerson),
|
('_model_meta_relating_basepeople_hidden_+', BasePerson),
|
||||||
('_relating_people_hidden_+', Person),
|
('_model_meta_relating_people_hidden_+', Person),
|
||||||
('BasePerson_following_abstract+', BasePerson),
|
('BasePerson_following_abstract+', BasePerson),
|
||||||
('BasePerson_following_abstract+', BasePerson),
|
('BasePerson_following_abstract+', BasePerson),
|
||||||
('BasePerson_following_base+', BasePerson),
|
('BasePerson_following_base+', BasePerson),
|
||||||
|
@ -483,7 +483,7 @@ TEST_RESULTS = {
|
||||||
),
|
),
|
||||||
BasePerson: (
|
BasePerson: (
|
||||||
('+', None),
|
('+', None),
|
||||||
('_relating_basepeople_hidden_+', None),
|
('_model_meta_relating_basepeople_hidden_+', None),
|
||||||
('BasePerson_following_abstract+', None),
|
('BasePerson_following_abstract+', None),
|
||||||
('BasePerson_following_abstract+', None),
|
('BasePerson_following_abstract+', None),
|
||||||
('BasePerson_following_base+', None),
|
('BasePerson_following_base+', None),
|
||||||
|
@ -822,7 +822,7 @@ TEST_RESULTS = {
|
||||||
('friends_base_rel_+', None),
|
('friends_base_rel_+', None),
|
||||||
('followers_base', None),
|
('followers_base', None),
|
||||||
('relating_basepeople', None),
|
('relating_basepeople', None),
|
||||||
('_relating_basepeople_hidden_+', None),
|
('_model_meta_relating_basepeople_hidden_+', None),
|
||||||
),
|
),
|
||||||
Person: (
|
Person: (
|
||||||
('friends_abstract_rel_+', BasePerson),
|
('friends_abstract_rel_+', BasePerson),
|
||||||
|
@ -830,7 +830,7 @@ TEST_RESULTS = {
|
||||||
('friends_base_rel_+', BasePerson),
|
('friends_base_rel_+', BasePerson),
|
||||||
('followers_base', BasePerson),
|
('followers_base', BasePerson),
|
||||||
('relating_basepeople', BasePerson),
|
('relating_basepeople', BasePerson),
|
||||||
('_relating_basepeople_hidden_+', BasePerson),
|
('_model_meta_relating_basepeople_hidden_+', BasePerson),
|
||||||
('friends_inherited_rel_+', None),
|
('friends_inherited_rel_+', None),
|
||||||
('followers_concrete', None),
|
('followers_concrete', None),
|
||||||
('relating_people', None),
|
('relating_people', None),
|
||||||
|
@ -849,7 +849,7 @@ TEST_RESULTS = {
|
||||||
'friends_base_rel_+',
|
'friends_base_rel_+',
|
||||||
'followers_base',
|
'followers_base',
|
||||||
'relating_basepeople',
|
'relating_basepeople',
|
||||||
'_relating_basepeople_hidden_+',
|
'_model_meta_relating_basepeople_hidden_+',
|
||||||
],
|
],
|
||||||
Person: [
|
Person: [
|
||||||
'friends_inherited_rel_+',
|
'friends_inherited_rel_+',
|
||||||
|
|
|
@ -257,7 +257,7 @@ class RelationTreeTests(SimpleTestCase):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(field.related_query_name() for field in BasePerson._meta._relation_tree),
|
sorted(field.related_query_name() for field in BasePerson._meta._relation_tree),
|
||||||
sorted([
|
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_following_abstract+', 'BasePerson_following_base+', 'BasePerson_following_base+',
|
||||||
'BasePerson_friends_abstract+', 'BasePerson_friends_abstract+', 'BasePerson_friends_base+',
|
'BasePerson_friends_abstract+', 'BasePerson_friends_abstract+', 'BasePerson_friends_base+',
|
||||||
'BasePerson_friends_base+', 'BasePerson_m2m_abstract+', 'BasePerson_m2m_base+', 'Relating_basepeople+',
|
'BasePerson_friends_base+', 'BasePerson_m2m_abstract+', 'BasePerson_m2m_base+', 'Relating_basepeople+',
|
||||||
|
|
Loading…
Reference in New Issue