1
0
mirror of https://github.com/django/django.git synced 2025-10-23 21:59:11 +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:
Alex Aktsipetrov
2019-10-15 01:59:43 +03:00
committed by Mariusz Felisiak
parent 70d8146986
commit 681f7e2b13
5 changed files with 64 additions and 4 deletions

View File

@@ -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):