1
0
mirror of https://github.com/django/django.git synced 2024-12-23 01:25:58 +00:00

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 # 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)

View File

@ -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):

View File

@ -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_+',

View File

@ -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+',