Fixed #17991 - prefetch_related fails with GenericRelation and varchar ID field

Thanks to okke@formsma.nl for the report, and carmandrew@gmail.com for the tests.
This commit is contained in:
Luke Plant 2012-10-29 13:40:32 +00:00
parent 4ea8105120
commit 4c4d08502c
3 changed files with 23 additions and 3 deletions

View File

@ -5,7 +5,6 @@ from __future__ import unicode_literals
from collections import defaultdict from collections import defaultdict
from functools import partial from functools import partial
from operator import attrgetter
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db import connection from django.db import connection
@ -329,8 +328,11 @@ def create_generic_related_manager(superclass):
set(obj._get_pk_val() for obj in instances) set(obj._get_pk_val() for obj in instances)
} }
qs = super(GenericRelatedObjectManager, self).get_query_set().using(db).filter(**query) qs = super(GenericRelatedObjectManager, self).get_query_set().using(db).filter(**query)
# 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
return (qs, return (qs,
attrgetter(self.object_id_field_name), lambda relobj: object_id_converter(getattr(relobj, self.object_id_field_name)),
lambda obj: obj._get_pk_val(), lambda obj: obj._get_pk_val(),
False, False,
self.prefetch_cache_name) self.prefetch_cache_name)

View File

@ -125,6 +125,10 @@ class TaggedItem(models.Model):
related_name='taggeditem_set3') related_name='taggeditem_set3')
created_by_fkey = models.PositiveIntegerField(null=True) created_by_fkey = models.PositiveIntegerField(null=True)
created_by = generic.GenericForeignKey('created_by_ct', 'created_by_fkey',) created_by = generic.GenericForeignKey('created_by_ct', 'created_by_fkey',)
favorite_ct = models.ForeignKey(ContentType, null=True,
related_name='taggeditem_set4')
favorite_fkey = models.CharField(max_length=64, null=True)
favorite = generic.GenericForeignKey('favorite_ct', 'favorite_fkey')
def __str__(self): def __str__(self):
return self.tag return self.tag
@ -132,7 +136,11 @@ class TaggedItem(models.Model):
class Bookmark(models.Model): class Bookmark(models.Model):
url = models.URLField() url = models.URLField()
tags = generic.GenericRelation(TaggedItem) tags = generic.GenericRelation(TaggedItem, related_name='bookmarks')
favorite_tags = generic.GenericRelation(TaggedItem,
content_type_field='favorite_ct',
object_id_field='favorite_fkey',
related_name='favorite_bookmarks')
class Comment(models.Model): class Comment(models.Model):

View File

@ -319,6 +319,16 @@ class GenericRelationTests(TestCase):
for t in b.tags.all()] for t in b.tags.all()]
self.assertEqual(sorted(tags), ["django", "python"]) self.assertEqual(sorted(tags), ["django", "python"])
def test_charfield_GFK(self):
b = Bookmark.objects.create(url='http://www.djangoproject.com/')
t1 = TaggedItem.objects.create(content_object=b, tag='django')
t2 = TaggedItem.objects.create(content_object=b, favorite=b, tag='python')
with self.assertNumQueries(3):
bookmark = Bookmark.objects.filter(pk=b.pk).prefetch_related('tags', 'favorite_tags')[0]
self.assertEqual(sorted([i.tag for i in bookmark.tags.all()]), ["django", "python"])
self.assertEqual([i.tag for i in bookmark.favorite_tags.all()], ["python"])
class MultiTableInheritanceTest(TestCase): class MultiTableInheritanceTest(TestCase):