mirror of https://github.com/django/django.git
Fixed #24156 -- Fixed inherited related name of ManyToManyField.
Fixed situation when parent abstract model declares related_name='+', and child models had an invalid queryset.
This commit is contained in:
parent
ec74dba2ab
commit
f7b2978158
|
@ -2626,7 +2626,7 @@ 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_+" % name
|
self.remote_field.related_name = "_%s_%s_+" % (cls.__name__.lower(), name)
|
||||||
|
|
||||||
super(ManyToManyField, self).contribute_to_class(cls, name, **kwargs)
|
super(ManyToManyField, self).contribute_to_class(cls, name, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -35,3 +35,20 @@ class Article(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('headline',)
|
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
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.db import transaction
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
from .models import Article, Publication
|
from .models import Article, InheritedArticleA, InheritedArticleB, Publication
|
||||||
|
|
||||||
|
|
||||||
class ManyToManyTests(TestCase):
|
class ManyToManyTests(TestCase):
|
||||||
|
@ -454,3 +454,28 @@ class ManyToManyTests(TestCase):
|
||||||
self.assertQuerysetEqual(self.a4.publications.all(), [])
|
self.assertQuerysetEqual(self.a4.publications.all(), [])
|
||||||
self.assertQuerysetEqual(self.p2.article_set.all(),
|
self.assertQuerysetEqual(self.p2.article_set.all(),
|
||||||
['<Article: NASA finds intelligent life on Earth>'])
|
['<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>',
|
||||||
|
])
|
||||||
|
|
|
@ -319,7 +319,7 @@ TEST_RESULTS = {
|
||||||
'get_all_related_objects_with_model_hidden_local': {
|
'get_all_related_objects_with_model_hidden_local': {
|
||||||
Person: (
|
Person: (
|
||||||
('+', None),
|
('+', None),
|
||||||
('_people_hidden_+', None),
|
('_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),
|
||||||
|
@ -334,7 +334,7 @@ TEST_RESULTS = {
|
||||||
),
|
),
|
||||||
BasePerson: (
|
BasePerson: (
|
||||||
('+', None),
|
('+', None),
|
||||||
('_basepeople_hidden_+', None),
|
('_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),
|
||||||
|
@ -382,8 +382,8 @@ TEST_RESULTS = {
|
||||||
Person: (
|
Person: (
|
||||||
('+', BasePerson),
|
('+', BasePerson),
|
||||||
('+', None),
|
('+', None),
|
||||||
('_basepeople_hidden_+', BasePerson),
|
('_relating_basepeople_hidden_+', BasePerson),
|
||||||
('_people_hidden_+', None),
|
('_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),
|
||||||
|
@ -416,7 +416,7 @@ TEST_RESULTS = {
|
||||||
),
|
),
|
||||||
BasePerson: (
|
BasePerson: (
|
||||||
('+', None),
|
('+', None),
|
||||||
('_basepeople_hidden_+', None),
|
('_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),
|
||||||
|
@ -730,7 +730,7 @@ TEST_RESULTS = {
|
||||||
('friends_base_rel_+', None),
|
('friends_base_rel_+', None),
|
||||||
('followers_base', None),
|
('followers_base', None),
|
||||||
('relating_basepeople', None),
|
('relating_basepeople', None),
|
||||||
('_basepeople_hidden_+', None),
|
('_relating_basepeople_hidden_+', None),
|
||||||
),
|
),
|
||||||
Person: (
|
Person: (
|
||||||
('friends_abstract_rel_+', BasePerson),
|
('friends_abstract_rel_+', BasePerson),
|
||||||
|
@ -738,11 +738,11 @@ TEST_RESULTS = {
|
||||||
('friends_base_rel_+', BasePerson),
|
('friends_base_rel_+', BasePerson),
|
||||||
('followers_base', BasePerson),
|
('followers_base', BasePerson),
|
||||||
('relating_basepeople', BasePerson),
|
('relating_basepeople', BasePerson),
|
||||||
('_basepeople_hidden_+', BasePerson),
|
('_relating_basepeople_hidden_+', BasePerson),
|
||||||
('friends_inherited_rel_+', None),
|
('friends_inherited_rel_+', None),
|
||||||
('followers_concrete', None),
|
('followers_concrete', None),
|
||||||
('relating_people', None),
|
('relating_people', None),
|
||||||
('_people_hidden_+', None),
|
('_relating_people_hidden_+', None),
|
||||||
),
|
),
|
||||||
Relation: (
|
Relation: (
|
||||||
('m2m_abstract_rel', None),
|
('m2m_abstract_rel', None),
|
||||||
|
@ -757,13 +757,13 @@ TEST_RESULTS = {
|
||||||
'friends_base_rel_+',
|
'friends_base_rel_+',
|
||||||
'followers_base',
|
'followers_base',
|
||||||
'relating_basepeople',
|
'relating_basepeople',
|
||||||
'_basepeople_hidden_+',
|
'_relating_basepeople_hidden_+',
|
||||||
],
|
],
|
||||||
Person: [
|
Person: [
|
||||||
'friends_inherited_rel_+',
|
'friends_inherited_rel_+',
|
||||||
'followers_concrete',
|
'followers_concrete',
|
||||||
'relating_people',
|
'relating_people',
|
||||||
'_people_hidden_+',
|
'_relating_people_hidden_+',
|
||||||
],
|
],
|
||||||
Relation: [
|
Relation: [
|
||||||
'm2m_abstract_rel',
|
'm2m_abstract_rel',
|
||||||
|
|
|
@ -248,7 +248,7 @@ class RelationTreeTests(TestCase):
|
||||||
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([
|
||||||
'+', '_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_following_base+', 'BasePerson_following_base+', 'BasePerson_friends_abstract+',
|
||||||
'BasePerson_friends_abstract+', 'BasePerson_friends_base+', 'BasePerson_friends_base+',
|
'BasePerson_friends_abstract+', 'BasePerson_friends_base+', 'BasePerson_friends_base+',
|
||||||
'BasePerson_m2m_abstract+', 'BasePerson_m2m_base+', 'Relating_basepeople+',
|
'BasePerson_m2m_abstract+', 'BasePerson_m2m_base+', 'Relating_basepeople+',
|
||||||
|
|
Loading…
Reference in New Issue