summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2023-10-06 20:18:41 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-10-06 20:19:59 +0200
commit9f8bf7aebe1d389aa06f41bcaccf5c4418c71026 (patch)
tree09f0d57de31a908c645e9da16210f6eea8a8c037
parentd5b093a2c5d968dc11447bc9b84848788f297737 (diff)
[5.0.x] Fixed #34889 -- Fixed get_prefetch_queryset() fallback in prefetch_one_level().
Thanks Matt Westcott for the report. Regression in cac94dd8aa2fb49cd2e06b5b37cf039257284bb0. Backport of 296b75a3c0309a936a6c07d8f711f722e3b96e63 from main
-rw-r--r--django/db/models/query.py7
-rw-r--r--tests/prefetch_related/tests.py44
2 files changed, 46 insertions, 5 deletions
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 1125302933..de00bba8d7 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -2550,6 +2550,9 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
RemovedInDjango60Warning,
stacklevel=2,
)
+ queryset = None
+ if querysets := lookup.get_current_querysets(level):
+ queryset = querysets[0]
(
rel_qs,
rel_obj_attr,
@@ -2557,9 +2560,7 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
single,
cache_name,
is_descriptor,
- ) = prefetcher.get_prefetch_queryset(
- instances, lookup.get_current_querysets(level)
- )
+ ) = prefetcher.get_prefetch_queryset(instances, queryset)
# We have to handle the possibility that the QuerySet we just got back
# contains some prefetch_related lookups. We don't want to trigger the
# prefetch_related functionality by evaluating the query. Rather, we need
diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py
index dd56664f68..08f87d55de 100644
--- a/tests/prefetch_related/tests.py
+++ b/tests/prefetch_related/tests.py
@@ -4,10 +4,12 @@ from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.db import NotSupportedError, connection
from django.db.models import Prefetch, QuerySet, prefetch_related_objects
-from django.db.models.query import get_prefetcher
+from django.db.models.fields.related import ForwardManyToOneDescriptor
+from django.db.models.query import get_prefetcher, prefetch_one_level
from django.db.models.sql import Query
from django.test import (
TestCase,
+ ignore_warnings,
override_settings,
skipIfDBFeature,
skipUnlessDBFeature,
@@ -1997,7 +1999,7 @@ class PrefetchLimitTests(TestDataMixin, TestCase):
list(Book.objects.prefetch_related(Prefetch("authors", authors[1:])))
-class GetCurrentQuerySetDeprecation(TestCase):
+class DeprecationTests(TestCase):
def test_get_current_queryset_warning(self):
msg = (
"Prefetch.get_current_queryset() is deprecated. Use "
@@ -2011,3 +2013,41 @@ class GetCurrentQuerySetDeprecation(TestCase):
)
with self.assertWarnsMessage(RemovedInDjango60Warning, msg):
self.assertIsNone(Prefetch("authors").get_current_queryset(1))
+
+ @ignore_warnings(category=RemovedInDjango60Warning)
+ def test_prefetch_one_level_fallback(self):
+ class NoGetPrefetchQuerySetsDescriptor(ForwardManyToOneDescriptor):
+ def get_prefetch_queryset(self, instances, queryset=None):
+ if queryset is None:
+ return super().get_prefetch_querysets(instances)
+ return super().get_prefetch_querysets(instances, [queryset])
+
+ def __getattribute__(self, name):
+ if name == "get_prefetch_querysets":
+ raise AttributeError
+ return super().__getattribute__(name)
+
+ house = House.objects.create()
+ room = Room.objects.create(house=house)
+ house.main_room = room
+ house.save()
+
+ # prefetch_one_level() fallbacks to get_prefetch_queryset().
+ prefetcher = NoGetPrefetchQuerySetsDescriptor(Room._meta.get_field("house"))
+ obj_list, additional_lookups = prefetch_one_level(
+ [room],
+ prefetcher,
+ Prefetch("house", House.objects.all()),
+ 0,
+ )
+ self.assertEqual(obj_list, [house])
+ self.assertEqual(additional_lookups, [])
+
+ obj_list, additional_lookups = prefetch_one_level(
+ [room],
+ prefetcher,
+ Prefetch("house"),
+ 0,
+ )
+ self.assertEqual(obj_list, [house])
+ self.assertEqual(additional_lookups, [])