From d5c19f9b327fccc1f707e10de648fe9d4cdacb9b Mon Sep 17 00:00:00 2001 From: Clifford Gama Date: Sat, 15 Mar 2025 11:13:46 +0200 Subject: [PATCH] Fixed #34819 -- Made GenericForeignKey prefetching use matching pk representations. Ensured that rel_obj_attr and instance_attr return matching (pk, cls) tuples in GenericForeignKey.get_prefetch_queryset(), preventing mismatches when prefetching related objects where pk and get_prep_value() differ. Using value_to_string() also makes this code compatible with composite primary keys. --- django/contrib/contenttypes/fields.py | 7 ++----- tests/prefetch_related/models.py | 9 +++++++++ tests/prefetch_related/tests.py | 9 +++++++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py index 272cb2b02c..f9d896bc13 100644 --- a/django/contrib/contenttypes/fields.py +++ b/django/contrib/contenttypes/fields.py @@ -205,14 +205,11 @@ class GenericForeignKey(FieldCacheMixin, Field): model = self.get_content_type( id=ct_id, using=obj._state.db ).model_class() - return ( - model._meta.pk.get_prep_value(getattr(obj, self.fk_field)), - model, - ) + return str(getattr(obj, self.fk_field)), model return ( ret_val, - lambda obj: (obj.pk, obj.__class__), + lambda obj: (obj._meta.pk.value_to_string(obj), obj.__class__), gfk_key, True, self.name, diff --git a/tests/prefetch_related/models.py b/tests/prefetch_related/models.py index 2f37cde1c8..e12eabdfb2 100644 --- a/tests/prefetch_related/models.py +++ b/tests/prefetch_related/models.py @@ -216,6 +216,15 @@ class Comment(models.Model): ordering = ["id"] +class ArticleCustomUUID(models.Model): + class CustomUUIDField(models.UUIDField): + def get_prep_value(self, value): + return str(value) + + id = CustomUUIDField(primary_key=True, default=uuid.uuid4) + name = models.CharField(max_length=30) + + # Models for lookup ordering tests diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py index 72c499df7f..49acfdd7c8 100644 --- a/tests/prefetch_related/tests.py +++ b/tests/prefetch_related/tests.py @@ -16,6 +16,7 @@ from django.test.utils import CaptureQueriesContext from .models import ( Article, + ArticleCustomUUID, Author, Author2, AuthorAddress, @@ -1179,6 +1180,14 @@ class GenericRelationTests(TestCase): qs = Comment.objects.prefetch_related("content_object_uuid") self.assertEqual([c.content_object_uuid for c in qs], [article]) + def test_prefetch_GFK_uses_prepped_primary_key(self): + article = ArticleCustomUUID.objects.create(name="Blanche") + Comment.objects.create(comment="Enchantment", content_object_uuid=article) + obj = Comment.objects.prefetch_related("content_object_uuid").get( + comment="Enchantment" + ) + self.assertEqual(obj.content_object_uuid, article) + def test_prefetch_GFK_fk_pk(self): book = Book.objects.create(title="Poems") book_with_year = BookWithYear.objects.create(book=book, published_year=2019)