summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Plant <L.Plant.98@cantab.net>2012-03-15 15:06:57 +0000
committerLuke Plant <L.Plant.98@cantab.net>2012-03-15 15:06:57 +0000
commitb018128ea5f9ad494afb0007c597bc61630dc087 (patch)
tree7aec61cecb404c5b9076f3e366a6ef3631fc77bf
parent8ef60df067a50d6d1f178bcf7aa285b6fa771dae (diff)
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
-rw-r--r--django/contrib/contenttypes/generic.py10
-rw-r--r--tests/modeltests/prefetch_related/models.py9
-rw-r--r--tests/modeltests/prefetch_related/tests.py10
-rw-r--r--tests/regressiontests/comment_tests/tests/model_tests.py7
4 files changed, 30 insertions, 6 deletions
diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py
index 5ed81a3664..a6732d7a2e 100644
--- a/django/contrib/contenttypes/generic.py
+++ b/django/contrib/contenttypes/generic.py
@@ -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__),
diff --git a/tests/modeltests/prefetch_related/models.py b/tests/modeltests/prefetch_related/models.py
index e6e4f89053..1dc034fa6c 100644
--- a/tests/modeltests/prefetch_related/models.py
+++ b/tests/modeltests/prefetch_related/models.py
@@ -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
diff --git a/tests/modeltests/prefetch_related/tests.py b/tests/modeltests/prefetch_related/tests.py
index 0a757271e2..b0bc435941 100644
--- a/tests/modeltests/prefetch_related/tests.py
+++ b/tests/modeltests/prefetch_related/tests.py
@@ -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
diff --git a/tests/regressiontests/comment_tests/tests/model_tests.py b/tests/regressiontests/comment_tests/tests/model_tests.py
index c7eaa4cef3..69c1a8118f 100644
--- a/tests/regressiontests/comment_tests/tests/model_tests.py
+++ b/tests/regressiontests/comment_tests/tests/model_tests.py
@@ -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]