Loading django/db/models/fields/related.py +1 −1 Original line number Diff line number Diff line Loading @@ -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) Loading tests/many_to_many/models.py +17 −0 Original line number Diff line number Diff line Loading @@ -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 tests/many_to_many/tests.py +26 −1 Original line number Diff line number Diff line Loading @@ -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): Loading Loading @@ -454,3 +454,28 @@ class ManyToManyTests(TestCase): self.assertQuerysetEqual(self.a4.publications.all(), []) self.assertQuerysetEqual(self.p2.article_set.all(), ['<Article: NASA finds intelligent life on Earth>']) 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(), [ '<Publication: Science News>', '<Publication: The Python Journal>', ]) self.assertQuerysetEqual(b.publications.all(), []) b.publications.add(self.p3) self.assertQuerysetEqual(a.publications.all(), [ '<Publication: Science News>', '<Publication: The Python Journal>', ]) self.assertQuerysetEqual(b.publications.all(), [ '<Publication: Science Weekly>', ]) tests/model_meta/results.py +10 −10 Original line number Diff line number Diff line Loading @@ -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), Loading @@ -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), Loading Loading @@ -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), Loading Loading @@ -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), Loading Loading @@ -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), Loading @@ -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), Loading @@ -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', Loading tests/model_meta/tests.py +1 −1 Original line number Diff line number Diff line Loading @@ -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+', Loading Loading
django/db/models/fields/related.py +1 −1 Original line number Diff line number Diff line Loading @@ -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) Loading
tests/many_to_many/models.py +17 −0 Original line number Diff line number Diff line Loading @@ -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
tests/many_to_many/tests.py +26 −1 Original line number Diff line number Diff line Loading @@ -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): Loading Loading @@ -454,3 +454,28 @@ class ManyToManyTests(TestCase): self.assertQuerysetEqual(self.a4.publications.all(), []) self.assertQuerysetEqual(self.p2.article_set.all(), ['<Article: NASA finds intelligent life on Earth>']) 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(), [ '<Publication: Science News>', '<Publication: The Python Journal>', ]) self.assertQuerysetEqual(b.publications.all(), []) b.publications.add(self.p3) self.assertQuerysetEqual(a.publications.all(), [ '<Publication: Science News>', '<Publication: The Python Journal>', ]) self.assertQuerysetEqual(b.publications.all(), [ '<Publication: Science Weekly>', ])
tests/model_meta/results.py +10 −10 Original line number Diff line number Diff line Loading @@ -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), Loading @@ -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), Loading Loading @@ -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), Loading Loading @@ -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), Loading Loading @@ -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), Loading @@ -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), Loading @@ -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', Loading
tests/model_meta/tests.py +1 −1 Original line number Diff line number Diff line Loading @@ -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+', Loading