Fixed #17696 - Queryset prefetch_related() ignores using()
Thanks to simon29 for the report. git-svn-id: http://code.djangoproject.com/svn/django/trunk@17605 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
413e37481d
commit
3db5b0e485
|
@ -321,7 +321,7 @@ def create_generic_related_manager(superclass):
|
||||||
return super(GenericRelatedObjectManager, self).get_query_set().using(db).filter(**self.core_filters)
|
return super(GenericRelatedObjectManager, self).get_query_set().using(db).filter(**self.core_filters)
|
||||||
|
|
||||||
def get_prefetch_query_set(self, instances):
|
def get_prefetch_query_set(self, instances):
|
||||||
db = self._db or router.db_for_read(self.model)
|
db = self._db or router.db_for_read(self.model, instance=instances[0])
|
||||||
query = {
|
query = {
|
||||||
'%s__pk' % self.content_type_field_name: self.content_type.id,
|
'%s__pk' % self.content_type_field_name: self.content_type.id,
|
||||||
'%s__in' % self.object_id_field_name:
|
'%s__in' % self.object_id_field_name:
|
||||||
|
|
|
@ -239,7 +239,7 @@ class SingleRelatedObjectDescriptor(object):
|
||||||
def get_prefetch_query_set(self, instances):
|
def get_prefetch_query_set(self, instances):
|
||||||
vals = set(instance._get_pk_val() for instance in instances)
|
vals = set(instance._get_pk_val() for instance in instances)
|
||||||
params = {'%s__pk__in' % self.related.field.name: vals}
|
params = {'%s__pk__in' % self.related.field.name: vals}
|
||||||
return (self.get_query_set(),
|
return (self.get_query_set(instance=instances[0]),
|
||||||
attrgetter(self.related.field.attname),
|
attrgetter(self.related.field.attname),
|
||||||
lambda obj: obj._get_pk_val(),
|
lambda obj: obj._get_pk_val(),
|
||||||
True,
|
True,
|
||||||
|
@ -322,7 +322,7 @@ class ReverseSingleRelatedObjectDescriptor(object):
|
||||||
params = {'%s__pk__in' % self.field.rel.field_name: vals}
|
params = {'%s__pk__in' % self.field.rel.field_name: vals}
|
||||||
else:
|
else:
|
||||||
params = {'%s__in' % self.field.rel.field_name: vals}
|
params = {'%s__in' % self.field.rel.field_name: vals}
|
||||||
return (self.get_query_set().filter(**params),
|
return (self.get_query_set(instance=instances[0]).filter(**params),
|
||||||
attrgetter(self.field.rel.field_name),
|
attrgetter(self.field.rel.field_name),
|
||||||
attrgetter(self.field.attname),
|
attrgetter(self.field.attname),
|
||||||
True,
|
True,
|
||||||
|
@ -461,7 +461,7 @@ class ForeignRelatedObjectsDescriptor(object):
|
||||||
return super(RelatedManager, self).get_query_set().using(db).filter(**self.core_filters)
|
return super(RelatedManager, self).get_query_set().using(db).filter(**self.core_filters)
|
||||||
|
|
||||||
def get_prefetch_query_set(self, instances):
|
def get_prefetch_query_set(self, instances):
|
||||||
db = self._db or router.db_for_read(self.model)
|
db = self._db or router.db_for_read(self.model, instance=instances[0])
|
||||||
query = {'%s__%s__in' % (rel_field.name, attname):
|
query = {'%s__%s__in' % (rel_field.name, attname):
|
||||||
set(getattr(obj, attname) for obj in instances)}
|
set(getattr(obj, attname) for obj in instances)}
|
||||||
qs = super(RelatedManager, self).get_query_set().using(db).filter(**query)
|
qs = super(RelatedManager, self).get_query_set().using(db).filter(**query)
|
||||||
|
@ -543,8 +543,9 @@ def create_many_related_manager(superclass, rel):
|
||||||
return super(ManyRelatedManager, self).get_query_set().using(db)._next_is_sticky().filter(**self.core_filters)
|
return super(ManyRelatedManager, self).get_query_set().using(db)._next_is_sticky().filter(**self.core_filters)
|
||||||
|
|
||||||
def get_prefetch_query_set(self, instances):
|
def get_prefetch_query_set(self, instances):
|
||||||
|
instance = instances[0]
|
||||||
from django.db import connections
|
from django.db import connections
|
||||||
db = self._db or router.db_for_read(self.model)
|
db = self._db or router.db_for_read(instance.__class__, instance=instance)
|
||||||
query = {'%s__pk__in' % self.query_field_name:
|
query = {'%s__pk__in' % self.query_field_name:
|
||||||
set(obj._get_pk_val() for obj in instances)}
|
set(obj._get_pk_val() for obj in instances)}
|
||||||
qs = super(ManyRelatedManager, self).get_query_set().using(db)._next_is_sticky().filter(**query)
|
qs = super(ManyRelatedManager, self).get_query_set().using(db)._next_is_sticky().filter(**query)
|
||||||
|
|
|
@ -483,3 +483,92 @@ class NullableTest(TestCase):
|
||||||
bulk = Employee.objects.prefetch_related('serfs').in_bulk([boss1.pk, boss2.pk])
|
bulk = Employee.objects.prefetch_related('serfs').in_bulk([boss1.pk, boss2.pk])
|
||||||
for b in bulk.values():
|
for b in bulk.values():
|
||||||
list(b.serfs.all())
|
list(b.serfs.all())
|
||||||
|
|
||||||
|
|
||||||
|
class MultiDbTests(TestCase):
|
||||||
|
multi_db = True
|
||||||
|
|
||||||
|
def test_using_is_honored_m2m(self):
|
||||||
|
B = Book.objects.using('other')
|
||||||
|
A = Author.objects.using('other')
|
||||||
|
book1 = B.create(title="Poems")
|
||||||
|
book2 = B.create(title="Jane Eyre")
|
||||||
|
book3 = B.create(title="Wuthering Heights")
|
||||||
|
book4 = B.create(title="Sense and Sensibility")
|
||||||
|
|
||||||
|
author1 = A.create(name="Charlotte", first_book=book1)
|
||||||
|
author2 = A.create(name="Anne", first_book=book1)
|
||||||
|
author3 = A.create(name="Emily", first_book=book1)
|
||||||
|
author4 = A.create(name="Jane", first_book=book4)
|
||||||
|
|
||||||
|
book1.authors.add(author1, author2, author3)
|
||||||
|
book2.authors.add(author1)
|
||||||
|
book3.authors.add(author3)
|
||||||
|
book4.authors.add(author4)
|
||||||
|
|
||||||
|
# Forward
|
||||||
|
qs1 = B.prefetch_related('authors')
|
||||||
|
with self.assertNumQueries(2, using='other'):
|
||||||
|
books = "".join(["%s (%s)\n" %
|
||||||
|
(book.title, ", ".join(a.name for a in book.authors.all()))
|
||||||
|
for book in qs1])
|
||||||
|
self.assertEqual(books,
|
||||||
|
"Poems (Charlotte, Anne, Emily)\n"
|
||||||
|
"Jane Eyre (Charlotte)\n"
|
||||||
|
"Wuthering Heights (Emily)\n"
|
||||||
|
"Sense and Sensibility (Jane)\n")
|
||||||
|
|
||||||
|
# Reverse
|
||||||
|
qs2 = A.prefetch_related('books')
|
||||||
|
with self.assertNumQueries(2, using='other'):
|
||||||
|
authors = "".join(["%s: %s\n" %
|
||||||
|
(author.name, ", ".join(b.title for b in author.books.all()))
|
||||||
|
for author in qs2])
|
||||||
|
self.assertEquals(authors,
|
||||||
|
"Charlotte: Poems, Jane Eyre\n"
|
||||||
|
"Anne: Poems\n"
|
||||||
|
"Emily: Poems, Wuthering Heights\n"
|
||||||
|
"Jane: Sense and Sensibility\n")
|
||||||
|
|
||||||
|
def test_using_is_honored_fkey(self):
|
||||||
|
B = Book.objects.using('other')
|
||||||
|
A = Author.objects.using('other')
|
||||||
|
book1 = B.create(title="Poems")
|
||||||
|
book2 = B.create(title="Sense and Sensibility")
|
||||||
|
|
||||||
|
author1 = A.create(name="Charlotte Bronte", first_book=book1)
|
||||||
|
author2 = A.create(name="Jane Austen", first_book=book2)
|
||||||
|
|
||||||
|
# Forward
|
||||||
|
with self.assertNumQueries(2, using='other'):
|
||||||
|
books = ", ".join(a.first_book.title for a in A.prefetch_related('first_book'))
|
||||||
|
self.assertEqual("Poems, Sense and Sensibility", books)
|
||||||
|
|
||||||
|
# Reverse
|
||||||
|
with self.assertNumQueries(2, using='other'):
|
||||||
|
books = "".join("%s (%s)\n" %
|
||||||
|
(b.title, ", ".join(a.name for a in b.first_time_authors.all()))
|
||||||
|
for b in B.prefetch_related('first_time_authors'))
|
||||||
|
self.assertEqual(books,
|
||||||
|
"Poems (Charlotte Bronte)\n"
|
||||||
|
"Sense and Sensibility (Jane Austen)\n")
|
||||||
|
|
||||||
|
def test_using_is_honored_inheritance(self):
|
||||||
|
B = BookWithYear.objects.using('other')
|
||||||
|
A = AuthorWithAge.objects.using('other')
|
||||||
|
book1 = B.create(title="Poems", published_year=2010)
|
||||||
|
book2 = B.create(title="More poems", published_year=2011)
|
||||||
|
author1 = A.create(name='Jane', first_book=book1, age=50)
|
||||||
|
author2 = A.create(name='Tom', first_book=book1, age=49)
|
||||||
|
|
||||||
|
# parent link
|
||||||
|
with self.assertNumQueries(2, using='other'):
|
||||||
|
authors = ", ".join(a.author.name for a in A.prefetch_related('author'))
|
||||||
|
|
||||||
|
self.assertEqual(authors, "Jane, Tom")
|
||||||
|
|
||||||
|
# child link
|
||||||
|
with self.assertNumQueries(2, using='other'):
|
||||||
|
ages = ", ".join(str(a.authorwithage.age) for a in A.prefetch_related('authorwithage'))
|
||||||
|
|
||||||
|
self.assertEqual(ages, "50, 49")
|
||||||
|
|
Loading…
Reference in New Issue