1
0
mirror of https://github.com/django/django.git synced 2025-10-31 09:41:08 +00:00

Fixed #28586 -- Added model field fetch modes.

May your database queries be much reduced with minimal effort.

co-authored-by: Andreas Pelme <andreas@pelme.se>
co-authored-by: Simon Charette <charette.s@gmail.com>
co-authored-by: Jacob Walls <jacobtylerwalls@gmail.com>
This commit is contained in:
Adam Johnson
2023-11-29 09:35:34 +00:00
committed by Jacob Walls
parent f6bd90c840
commit e097e8a12f
24 changed files with 682 additions and 73 deletions

View File

@@ -1,7 +1,8 @@
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.prefetch import GenericPrefetch
from django.core.exceptions import FieldError
from django.core.exceptions import FieldError, FieldFetchBlocked
from django.db.models import Q, prefetch_related_objects
from django.db.models.fetch_modes import FETCH_PEERS, RAISE
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
from .models import (
@@ -780,6 +781,46 @@ class GenericRelationsTests(TestCase):
self.platypus.latin_name,
)
def test_fetch_mode_fetch_peers(self):
TaggedItem.objects.bulk_create(
[
TaggedItem(tag="lion", content_object=self.lion),
TaggedItem(tag="platypus", content_object=self.platypus),
TaggedItem(tag="quartz", content_object=self.quartz),
]
)
# Peers fetching should fetch all related peers GFKs at once which is
# one query per content type.
with self.assertNumQueries(1):
quartz_tag, platypus_tag, lion_tag = TaggedItem.objects.fetch_mode(
FETCH_PEERS
).order_by("-pk")[:3]
with self.assertNumQueries(2):
self.assertEqual(lion_tag.content_object, self.lion)
with self.assertNumQueries(0):
self.assertEqual(platypus_tag.content_object, self.platypus)
self.assertEqual(quartz_tag.content_object, self.quartz)
# It should ignore already cached instances though.
with self.assertNumQueries(1):
quartz_tag, platypus_tag, lion_tag = TaggedItem.objects.fetch_mode(
FETCH_PEERS
).order_by("-pk")[:3]
with self.assertNumQueries(2):
self.assertEqual(quartz_tag.content_object, self.quartz)
self.assertEqual(lion_tag.content_object, self.lion)
with self.assertNumQueries(0):
self.assertEqual(platypus_tag.content_object, self.platypus)
self.assertEqual(quartz_tag.content_object, self.quartz)
def test_fetch_mode_raise(self):
TaggedItem.objects.create(tag="lion", content_object=self.lion)
tag = TaggedItem.objects.fetch_mode(RAISE).get(tag="yellow")
msg = "Fetching of TaggedItem.content_object blocked."
with self.assertRaisesMessage(FieldFetchBlocked, msg) as cm:
tag.content_object
self.assertIsNone(cm.exception.__cause__)
self.assertTrue(cm.exception.__suppress_context__)
class ProxyRelatedModelTest(TestCase):
def test_default_behavior(self):