1
0
mirror of https://github.com/django/django.git synced 2025-06-05 11:39:13 +00:00

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.
This commit is contained in:
Clifford Gama 2025-03-15 11:13:46 +02:00 committed by Sarah Boyce
parent 7d9aab8da0
commit d5c19f9b32
3 changed files with 20 additions and 5 deletions

View File

@ -205,14 +205,11 @@ class GenericForeignKey(FieldCacheMixin, Field):
model = self.get_content_type( model = self.get_content_type(
id=ct_id, using=obj._state.db id=ct_id, using=obj._state.db
).model_class() ).model_class()
return ( return str(getattr(obj, self.fk_field)), model
model._meta.pk.get_prep_value(getattr(obj, self.fk_field)),
model,
)
return ( return (
ret_val, ret_val,
lambda obj: (obj.pk, obj.__class__), lambda obj: (obj._meta.pk.value_to_string(obj), obj.__class__),
gfk_key, gfk_key,
True, True,
self.name, self.name,

View File

@ -216,6 +216,15 @@ class Comment(models.Model):
ordering = ["id"] 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 # Models for lookup ordering tests

View File

@ -16,6 +16,7 @@ from django.test.utils import CaptureQueriesContext
from .models import ( from .models import (
Article, Article,
ArticleCustomUUID,
Author, Author,
Author2, Author2,
AuthorAddress, AuthorAddress,
@ -1179,6 +1180,14 @@ class GenericRelationTests(TestCase):
qs = Comment.objects.prefetch_related("content_object_uuid") qs = Comment.objects.prefetch_related("content_object_uuid")
self.assertEqual([c.content_object_uuid for c in qs], [article]) 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): def test_prefetch_GFK_fk_pk(self):
book = Book.objects.create(title="Poems") book = Book.objects.create(title="Poems")
book_with_year = BookWithYear.objects.create(book=book, published_year=2019) book_with_year = BookWithYear.objects.create(book=book, published_year=2019)