Skip to content

Commit 296b75a

Browse files
authored
Fixed #34889 -- Fixed get_prefetch_queryset() fallback in prefetch_one_level().
Thanks Matt Westcott for the report. Regression in cac94dd.
1 parent 90c75dc commit 296b75a

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

django/db/models/query.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2550,16 +2550,17 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
25502550
RemovedInDjango60Warning,
25512551
stacklevel=2,
25522552
)
2553+
queryset = None
2554+
if querysets := lookup.get_current_querysets(level):
2555+
queryset = querysets[0]
25532556
(
25542557
rel_qs,
25552558
rel_obj_attr,
25562559
instance_attr,
25572560
single,
25582561
cache_name,
25592562
is_descriptor,
2560-
) = prefetcher.get_prefetch_queryset(
2561-
instances, lookup.get_current_querysets(level)
2562-
)
2563+
) = prefetcher.get_prefetch_queryset(instances, queryset)
25632564
# We have to handle the possibility that the QuerySet we just got back
25642565
# contains some prefetch_related lookups. We don't want to trigger the
25652566
# prefetch_related functionality by evaluating the query. Rather, we need

tests/prefetch_related/tests.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
from django.core.exceptions import ObjectDoesNotExist
55
from django.db import NotSupportedError, connection
66
from django.db.models import Prefetch, QuerySet, prefetch_related_objects
7-
from django.db.models.query import get_prefetcher
7+
from django.db.models.fields.related import ForwardManyToOneDescriptor
8+
from django.db.models.query import get_prefetcher, prefetch_one_level
89
from django.db.models.sql import Query
910
from django.test import (
1011
TestCase,
12+
ignore_warnings,
1113
override_settings,
1214
skipIfDBFeature,
1315
skipUnlessDBFeature,
@@ -1997,7 +1999,7 @@ def test_window_not_supported(self):
19971999
list(Book.objects.prefetch_related(Prefetch("authors", authors[1:])))
19982000

19992001

2000-
class GetCurrentQuerySetDeprecation(TestCase):
2002+
class DeprecationTests(TestCase):
20012003
def test_get_current_queryset_warning(self):
20022004
msg = (
20032005
"Prefetch.get_current_queryset() is deprecated. Use "
@@ -2011,3 +2013,41 @@ def test_get_current_queryset_warning(self):
20112013
)
20122014
with self.assertWarnsMessage(RemovedInDjango60Warning, msg):
20132015
self.assertIsNone(Prefetch("authors").get_current_queryset(1))
2016+
2017+
@ignore_warnings(category=RemovedInDjango60Warning)
2018+
def test_prefetch_one_level_fallback(self):
2019+
class NoGetPrefetchQuerySetsDescriptor(ForwardManyToOneDescriptor):
2020+
def get_prefetch_queryset(self, instances, queryset=None):
2021+
if queryset is None:
2022+
return super().get_prefetch_querysets(instances)
2023+
return super().get_prefetch_querysets(instances, [queryset])
2024+
2025+
def __getattribute__(self, name):
2026+
if name == "get_prefetch_querysets":
2027+
raise AttributeError
2028+
return super().__getattribute__(name)
2029+
2030+
house = House.objects.create()
2031+
room = Room.objects.create(house=house)
2032+
house.main_room = room
2033+
house.save()
2034+
2035+
# prefetch_one_level() fallbacks to get_prefetch_queryset().
2036+
prefetcher = NoGetPrefetchQuerySetsDescriptor(Room._meta.get_field("house"))
2037+
obj_list, additional_lookups = prefetch_one_level(
2038+
[room],
2039+
prefetcher,
2040+
Prefetch("house", House.objects.all()),
2041+
0,
2042+
)
2043+
self.assertEqual(obj_list, [house])
2044+
self.assertEqual(additional_lookups, [])
2045+
2046+
obj_list, additional_lookups = prefetch_one_level(
2047+
[room],
2048+
prefetcher,
2049+
Prefetch("house"),
2050+
0,
2051+
)
2052+
self.assertEqual(obj_list, [house])
2053+
self.assertEqual(additional_lookups, [])

0 commit comments

Comments
 (0)