Fixed #17838 - prefetch_related fails for GenericForeignKeys when related object id is not a CharField/TextField
Thanks to mkai for the report and debugging, and tmitchell and Przemek Lewandowski for their work on the patch. git-svn-id: http://code.djangoproject.com/svn/django/trunk@17744 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
8ef60df067
commit
b018128ea5
|
@ -85,16 +85,16 @@ class GenericForeignKey(object):
|
|||
ret_val.extend(ct.get_all_objects_for_this_type(pk__in=fkeys))
|
||||
|
||||
# For doing the join in Python, we have to match both the FK val and the
|
||||
# content type, so the 'attr' vals we return need to be callables that
|
||||
# will return a (fk, class) pair.
|
||||
# content type, so we use a callable that returns a (fk, class) pair.
|
||||
def gfk_key(obj):
|
||||
ct_id = getattr(obj, ct_attname)
|
||||
if ct_id is None:
|
||||
return None
|
||||
else:
|
||||
return (getattr(obj, self.fk_field),
|
||||
self.get_content_type(id=ct_id,
|
||||
using=obj._state.db).model_class())
|
||||
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 (ret_val,
|
||||
lambda obj: (obj._get_pk_val(), obj.__class__),
|
||||
|
|
|
@ -125,6 +125,15 @@ class Bookmark(models.Model):
|
|||
tags = generic.GenericRelation(TaggedItem)
|
||||
|
||||
|
||||
class Comment(models.Model):
|
||||
comment = models.TextField()
|
||||
|
||||
# Content-object field
|
||||
content_type = models.ForeignKey(ContentType)
|
||||
object_pk = models.TextField()
|
||||
content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk")
|
||||
|
||||
|
||||
## Models for lookup ordering tests
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.test import TestCase
|
|||
|
||||
from .models import (Author, Book, Reader, Qualification, Teacher, Department,
|
||||
TaggedItem, Bookmark, AuthorAddress, FavoriteAuthors, AuthorWithAge,
|
||||
BookWithYear, Person, House, Room, Employee)
|
||||
BookWithYear, Person, House, Room, Employee, Comment)
|
||||
|
||||
|
||||
class PrefetchRelatedTests(TestCase):
|
||||
|
@ -254,6 +254,14 @@ class GenericRelationTests(TestCase):
|
|||
qs = TaggedItem.objects.prefetch_related('content_object')
|
||||
list(qs)
|
||||
|
||||
def test_prefetch_GFK_nonint_pk(self):
|
||||
Comment.objects.create(comment="awesome", content_object=self.book1)
|
||||
|
||||
# 1 for Comment table, 1 for Book table
|
||||
with self.assertNumQueries(2):
|
||||
qs = Comment.objects.prefetch_related('content_object')
|
||||
[c.content_object for c in qs]
|
||||
|
||||
def test_traverse_GFK(self):
|
||||
"""
|
||||
Test that we can traverse a 'content_object' with prefetch_related() and
|
||||
|
|
|
@ -49,3 +49,10 @@ class CommentManagerTests(CommentTestCase):
|
|||
author_comments = list(Comment.objects.for_model(Author.objects.get(pk=1)))
|
||||
self.assertEqual(article_comments, [c1, c3])
|
||||
self.assertEqual(author_comments, [c2])
|
||||
|
||||
def testPrefetchRelated(self):
|
||||
c1, c2, c3, c4 = self.createSomeComments()
|
||||
# one for comments, one for Articles, one for Author
|
||||
with self.assertNumQueries(3):
|
||||
qs = Comment.objects.prefetch_related('content_object')
|
||||
[c.content_object for c in qs]
|
||||
|
|
Loading…
Reference in New Issue