From 4ab027b94409e6415b774797bf9d3593da9d9ea8 Mon Sep 17 00:00:00 2001 From: robwa Date: Tue, 13 Mar 2018 03:42:48 +0100 Subject: [PATCH] Fixed #28988 -- Fixed queries when a GenericRelation is used with multi-table inheritance. --- django/contrib/contenttypes/fields.py | 8 ++++++++ django/db/models/base.py | 4 +++- tests/generic_relations_regress/models.py | 2 +- tests/generic_relations_regress/tests.py | 10 ++++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py index d186e1f39a..e55766aa6f 100644 --- a/django/contrib/contenttypes/fields.py +++ b/django/contrib/contenttypes/fields.py @@ -283,6 +283,8 @@ class GenericRelation(ForeignObject): rel_class = GenericRel + mti_inherited = False + def __init__(self, to, object_id_field='object_id', content_type_field='content_type', for_concrete_model=True, related_query_name=None, limit_choices_to=None, **kwargs): kwargs['rel'] = self.rel_class( @@ -427,6 +429,12 @@ class GenericRelation(ForeignObject): kwargs['private_only'] = True super().contribute_to_class(cls, name, **kwargs) self.model = cls + # Disable the reverse relation for fields inherited by subclasses of a + # model in multi-table inheritance. The reverse relation points to the + # field of the base model. + if self.mti_inherited: + self.remote_field.related_name = '+' + self.remote_field.related_query_name = None setattr(cls, self.name, ReverseGenericManyToOneDescriptor(self.remote_field)) # Add get_RELATED_order() and set_RELATED_order() to the model this diff --git a/django/db/models/base.py b/django/db/models/base.py index 20d1c73ddf..9af6a8f92d 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -278,7 +278,9 @@ class ModelBase(type): ) ) else: - new_class.add_to_class(field.name, copy.deepcopy(field)) + field = copy.deepcopy(field) + field.mti_inherited = True + new_class.add_to_class(field.name, field) # Copy indexes so that index names are unique when models extend an # abstract model. diff --git a/tests/generic_relations_regress/models.py b/tests/generic_relations_regress/models.py index c9572eb961..5d8716aa0c 100644 --- a/tests/generic_relations_regress/models.py +++ b/tests/generic_relations_regress/models.py @@ -26,7 +26,7 @@ class LinkProxy(Link): class Place(models.Model): name = models.CharField(max_length=100) - links = GenericRelation(Link) + links = GenericRelation(Link, related_query_name='places') link_proxy = GenericRelation(LinkProxy) def __str__(self): diff --git a/tests/generic_relations_regress/tests.py b/tests/generic_relations_regress/tests.py index 91158d8198..769a64d0f1 100644 --- a/tests/generic_relations_regress/tests.py +++ b/tests/generic_relations_regress/tests.py @@ -263,3 +263,13 @@ class GenericRelationTests(TestCase): place = Place.objects.create() Link.objects.create(content_object=place) self.assertEqual(Place.objects.get(link_proxy__object_id=place.id), place) + + def test_generic_reverse_relation_with_mti(self): + """ + Filtering with a reverse generic relation, where the GenericRelation + comes from multi-table inheritance. + """ + place = Place.objects.create(name='Test Place') + link = Link.objects.create(content_object=place) + result = Link.objects.filter(places=place) + self.assertCountEqual(result, [link])