[1.8.x] Fixed #24156 -- Fixed inherited related name of ManyToManyField.

Fixed situation when parent abstract model declares related_name='+'
and child models had an invalid queryset.

Backport of f7b2978158 from master
This commit is contained in:
Andriy Sokolovskiy 2015-05-09 13:57:13 +03:00 committed by Tim Graham
parent 15359f1fe9
commit eb85e6672a
6 changed files with 59 additions and 13 deletions

View File

@ -2540,7 +2540,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.rel.related_name = "_%s_+" % name
self.rel.related_name = "_%s_%s_+" % (cls.__name__.lower(), name)
super(ManyToManyField, self).contribute_to_class(cls, name, **kwargs)

View File

@ -17,3 +17,7 @@ Bugfixes
* Fixed system check crash on ``ForeignKey`` to abstract model
(:ticket:`25503`).
* Fixed incorrect queries when you have multiple ``ManyToManyField``\s on
different models that have the same field name, point to the same model, and
have their reverse relations disabled (:ticket:`25545`).

View File

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

View File

@ -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):
@ -415,3 +415,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>',
])

View File

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

View File

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