mirror of
https://github.com/django/django.git
synced 2025-10-24 06:06:09 +00:00
Fixed #20577 -- Deferred filtering of prefetched related querysets.
Added internal interface to QuerySet that allows to defer next filter call till .query is accessed. Used it to optimize prefetch_related(). Thanks Simon Charette for the review.
This commit is contained in:
committed by
Mariusz Felisiak
parent
70d8146986
commit
681f7e2b13
@@ -5,6 +5,7 @@ from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db import connection
|
||||
from django.db.models import Prefetch, QuerySet
|
||||
from django.db.models.query import get_prefetcher, prefetch_related_objects
|
||||
from django.db.models.sql import Query
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test.utils import CaptureQueriesContext
|
||||
|
||||
@@ -291,6 +292,20 @@ class PrefetchRelatedTests(TestDataMixin, TestCase):
|
||||
sql = queries[-1]['sql']
|
||||
self.assertWhereContains(sql, self.author1.id)
|
||||
|
||||
def test_filter_deferred(self):
|
||||
"""
|
||||
Related filtering of prefetched querysets is deferred until necessary.
|
||||
"""
|
||||
add_q = Query.add_q
|
||||
with mock.patch.object(
|
||||
Query,
|
||||
'add_q',
|
||||
autospec=True,
|
||||
side_effect=lambda self, q: add_q(self, q),
|
||||
) as add_q_mock:
|
||||
list(Book.objects.prefetch_related('authors'))
|
||||
self.assertEqual(add_q_mock.call_count, 1)
|
||||
|
||||
|
||||
class RawQuerySetTests(TestDataMixin, TestCase):
|
||||
def test_basic(self):
|
||||
@@ -823,6 +838,22 @@ class CustomPrefetchTests(TestCase):
|
||||
with self.assertNumQueries(0):
|
||||
self.assertEqual(person.cached_all_houses, all_houses)
|
||||
|
||||
def test_filter_deferred(self):
|
||||
"""
|
||||
Related filtering of prefetched querysets is deferred until necessary.
|
||||
"""
|
||||
add_q = Query.add_q
|
||||
with mock.patch.object(
|
||||
Query,
|
||||
'add_q',
|
||||
autospec=True,
|
||||
side_effect=lambda self, q: add_q(self, q),
|
||||
) as add_q_mock:
|
||||
list(House.objects.prefetch_related(
|
||||
Prefetch('occupants', queryset=Person.objects.all())
|
||||
))
|
||||
self.assertEqual(add_q_mock.call_count, 1)
|
||||
|
||||
|
||||
class DefaultManagerTests(TestCase):
|
||||
|
||||
|
||||
@@ -212,6 +212,12 @@ class PickleabilityTestCase(TestCase):
|
||||
qs = Happening.objects.annotate(latest_time=models.Max('when'))
|
||||
self.assert_pickles(qs)
|
||||
|
||||
def test_filter_deferred(self):
|
||||
qs = Happening.objects.all()
|
||||
qs._defer_next_filter = True
|
||||
qs = qs.filter(id=0)
|
||||
self.assert_pickles(qs)
|
||||
|
||||
def test_missing_django_version_unpickling(self):
|
||||
"""
|
||||
#21430 -- Verifies a warning is raised for querysets that are
|
||||
|
||||
Reference in New Issue
Block a user