diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 45690376055..15d032dc1fb 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -2626,7 +2626,7 @@ 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_+" % name + self.remote_field.related_name = "_%s_%s_+" % (cls.__name__.lower(), name) super(ManyToManyField, self).contribute_to_class(cls, name, **kwargs) diff --git a/tests/many_to_many/models.py b/tests/many_to_many/models.py index 9e578e4e0b6..5688c853d6d 100644 --- a/tests/many_to_many/models.py +++ b/tests/many_to_many/models.py @@ -35,3 +35,20 @@ class Article(models.Model): class Meta: ordering = ('headline',) + + +# Models to test correct related_name inheritance +class AbstractArticle(models.Model): + class Meta: + abstract = True + ordering = ('title',) + + publications = models.ManyToManyField(Publication, name='publications', related_name='+') + + +class InheritedArticleA(AbstractArticle): + pass + + +class InheritedArticleB(AbstractArticle): + pass diff --git a/tests/many_to_many/tests.py b/tests/many_to_many/tests.py index 387acb25808..ffe5e879ca7 100644 --- a/tests/many_to_many/tests.py +++ b/tests/many_to_many/tests.py @@ -4,7 +4,7 @@ from django.db import transaction from django.test import TestCase from django.utils import six -from .models import Article, Publication +from .models import Article, InheritedArticleA, InheritedArticleB, Publication class ManyToManyTests(TestCase): @@ -454,3 +454,28 @@ class ManyToManyTests(TestCase): self.assertQuerysetEqual(self.a4.publications.all(), []) self.assertQuerysetEqual(self.p2.article_set.all(), ['']) + + def test_inherited_models_selects(self): + """ + #24156 - Objects from child models where the parent's m2m field uses + related_name='+' should be retrieved correctly. + """ + a = InheritedArticleA.objects.create() + b = InheritedArticleB.objects.create() + a.publications.add(self.p1, self.p2) + self.assertQuerysetEqual(a.publications.all(), + [ + '', + '', + ]) + self.assertQuerysetEqual(b.publications.all(), []) + b.publications.add(self.p3) + self.assertQuerysetEqual(a.publications.all(), + [ + '', + '', + ]) + self.assertQuerysetEqual(b.publications.all(), + [ + '', + ]) diff --git a/tests/model_meta/results.py b/tests/model_meta/results.py index 0770b86b2ae..a4d9010da8a 100644 --- a/tests/model_meta/results.py +++ b/tests/model_meta/results.py @@ -319,7 +319,7 @@ TEST_RESULTS = { 'get_all_related_objects_with_model_hidden_local': { Person: ( ('+', None), - ('_people_hidden_+', None), + ('_relating_people_hidden_+', None), ('Person_following_inherited+', None), ('Person_following_inherited+', None), ('Person_friends_inherited+', None), @@ -334,7 +334,7 @@ TEST_RESULTS = { ), BasePerson: ( ('+', None), - ('_basepeople_hidden_+', None), + ('_relating_basepeople_hidden_+', None), ('BasePerson_following_abstract+', None), ('BasePerson_following_abstract+', None), ('BasePerson_following_base+', None), @@ -382,8 +382,8 @@ TEST_RESULTS = { Person: ( ('+', BasePerson), ('+', None), - ('_basepeople_hidden_+', BasePerson), - ('_people_hidden_+', None), + ('_relating_basepeople_hidden_+', BasePerson), + ('_relating_people_hidden_+', None), ('BasePerson_following_abstract+', BasePerson), ('BasePerson_following_abstract+', BasePerson), ('BasePerson_following_base+', BasePerson), @@ -416,7 +416,7 @@ TEST_RESULTS = { ), BasePerson: ( ('+', None), - ('_basepeople_hidden_+', None), + ('_relating_basepeople_hidden_+', None), ('BasePerson_following_abstract+', None), ('BasePerson_following_abstract+', None), ('BasePerson_following_base+', None), @@ -730,7 +730,7 @@ TEST_RESULTS = { ('friends_base_rel_+', None), ('followers_base', None), ('relating_basepeople', None), - ('_basepeople_hidden_+', None), + ('_relating_basepeople_hidden_+', None), ), Person: ( ('friends_abstract_rel_+', BasePerson), @@ -738,11 +738,11 @@ TEST_RESULTS = { ('friends_base_rel_+', BasePerson), ('followers_base', BasePerson), ('relating_basepeople', BasePerson), - ('_basepeople_hidden_+', BasePerson), + ('_relating_basepeople_hidden_+', BasePerson), ('friends_inherited_rel_+', None), ('followers_concrete', None), ('relating_people', None), - ('_people_hidden_+', None), + ('_relating_people_hidden_+', None), ), Relation: ( ('m2m_abstract_rel', None), @@ -757,13 +757,13 @@ TEST_RESULTS = { 'friends_base_rel_+', 'followers_base', 'relating_basepeople', - '_basepeople_hidden_+', + '_relating_basepeople_hidden_+', ], Person: [ 'friends_inherited_rel_+', 'followers_concrete', 'relating_people', - '_people_hidden_+', + '_relating_people_hidden_+', ], Relation: [ 'm2m_abstract_rel', diff --git a/tests/model_meta/tests.py b/tests/model_meta/tests.py index 390c0fe988f..0db3f661512 100644 --- a/tests/model_meta/tests.py +++ b/tests/model_meta/tests.py @@ -248,7 +248,7 @@ class RelationTreeTests(TestCase): self.assertEqual( sorted([field.related_query_name() for field in BasePerson._meta._relation_tree]), sorted([ - '+', '_basepeople_hidden_+', 'BasePerson_following_abstract+', 'BasePerson_following_abstract+', + '+', '_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+',