From 0b013564ef0609d95b1d263626f2e15bccda1a50 Mon Sep 17 00:00:00 2001 From: Eugene Hatsko Date: Tue, 21 Jan 2020 10:12:25 +0300 Subject: [PATCH] Fixed #31190 -- Fixed prefetch_related() crash for GenericForeignKey with custom ContentType foreign key. Regression in dffa3e1992562ba60512d96d1eb5859ffff2ceb5. --- django/contrib/contenttypes/fields.py | 3 ++- docs/releases/3.0.3.txt | 4 ++++ tests/generic_relations/tests.py | 13 +++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py index 4015f16c6b0..163e3a9c501 100644 --- a/django/contrib/contenttypes/fields.py +++ b/django/contrib/contenttypes/fields.py @@ -583,11 +583,12 @@ def create_generic_related_manager(superclass, rel): # We (possibly) need to convert object IDs to the type of the # instances' PK in order to match up instances: object_id_converter = instances[0]._meta.pk.to_python + content_type_id_field_name = '%s_id' % self.content_type_field_name return ( queryset.filter(query), lambda relobj: ( object_id_converter(getattr(relobj, self.object_id_field_name)), - relobj.content_type_id + getattr(relobj, content_type_id_field_name), ), lambda obj: (obj.pk, self.get_content_type(obj).pk), False, diff --git a/docs/releases/3.0.3.txt b/docs/releases/3.0.3.txt index 2726e2d3ab1..ed92938e091 100644 --- a/docs/releases/3.0.3.txt +++ b/docs/releases/3.0.3.txt @@ -35,3 +35,7 @@ Bugfixes * Fixed a regression in Django 2.2.7 that caused :meth:`~django.db.models.Model.get_FOO_display` to work incorrectly when overriding inherited choices (:ticket:`31124`). + +* Fixed a regression in Django 3.0 that caused a crash of + ``QuerySet.prefetch_related()`` for ``GenericForeignKey`` with a custom + ``ContentType`` foreign key (:ticket:`31190`). diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py index 7c0db959089..683efaddfb7 100644 --- a/tests/generic_relations/tests.py +++ b/tests/generic_relations/tests.py @@ -564,6 +564,19 @@ class GenericRelationsTests(TestCase): for tag in tags: self.assertSequenceEqual(tag.content_object.tags.all(), [tag]) + def test_prefetch_related_custom_object_id(self): + tiger = Animal.objects.create(common_name='tiger') + cheetah = Animal.objects.create(common_name='cheetah') + Comparison.objects.create( + first_obj=cheetah, other_obj=tiger, comparative='faster', + ) + Comparison.objects.create( + first_obj=tiger, other_obj=cheetah, comparative='cooler', + ) + qs = Comparison.objects.prefetch_related('first_obj__comparisons') + for comparison in qs: + self.assertSequenceEqual(comparison.first_obj.comparisons.all(), [comparison]) + class ProxyRelatedModelTest(TestCase): def test_default_behavior(self):