mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[5.0.x] Fixed #34889 -- Fixed get_prefetch_queryset() fallback in prefetch_one_level().
Thanks Matt Westcott for the report. Regression incac94dd8aa. Backport of296b75a3c0from main
This commit is contained in:
		| @@ -2550,6 +2550,9 @@ def prefetch_one_level(instances, prefetcher, lookup, level): | |||||||
|             RemovedInDjango60Warning, |             RemovedInDjango60Warning, | ||||||
|             stacklevel=2, |             stacklevel=2, | ||||||
|         ) |         ) | ||||||
|  |         queryset = None | ||||||
|  |         if querysets := lookup.get_current_querysets(level): | ||||||
|  |             queryset = querysets[0] | ||||||
|         ( |         ( | ||||||
|             rel_qs, |             rel_qs, | ||||||
|             rel_obj_attr, |             rel_obj_attr, | ||||||
| @@ -2557,9 +2560,7 @@ def prefetch_one_level(instances, prefetcher, lookup, level): | |||||||
|             single, |             single, | ||||||
|             cache_name, |             cache_name, | ||||||
|             is_descriptor, |             is_descriptor, | ||||||
|         ) = prefetcher.get_prefetch_queryset( |         ) = prefetcher.get_prefetch_queryset(instances, queryset) | ||||||
|             instances, lookup.get_current_querysets(level) |  | ||||||
|         ) |  | ||||||
|     # We have to handle the possibility that the QuerySet we just got back |     # 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 |     # contains some prefetch_related lookups. We don't want to trigger the | ||||||
|     # prefetch_related functionality by evaluating the query. Rather, we need |     # prefetch_related functionality by evaluating the query. Rather, we need | ||||||
|   | |||||||
| @@ -4,10 +4,12 @@ from django.contrib.contenttypes.models import ContentType | |||||||
| from django.core.exceptions import ObjectDoesNotExist | from django.core.exceptions import ObjectDoesNotExist | ||||||
| from django.db import NotSupportedError, connection | from django.db import NotSupportedError, connection | ||||||
| from django.db.models import Prefetch, QuerySet, prefetch_related_objects | 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.db.models.sql import Query | ||||||
| from django.test import ( | from django.test import ( | ||||||
|     TestCase, |     TestCase, | ||||||
|  |     ignore_warnings, | ||||||
|     override_settings, |     override_settings, | ||||||
|     skipIfDBFeature, |     skipIfDBFeature, | ||||||
|     skipUnlessDBFeature, |     skipUnlessDBFeature, | ||||||
| @@ -1997,7 +1999,7 @@ class PrefetchLimitTests(TestDataMixin, TestCase): | |||||||
|             list(Book.objects.prefetch_related(Prefetch("authors", authors[1:]))) |             list(Book.objects.prefetch_related(Prefetch("authors", authors[1:]))) | ||||||
|  |  | ||||||
|  |  | ||||||
| class GetCurrentQuerySetDeprecation(TestCase): | class DeprecationTests(TestCase): | ||||||
|     def test_get_current_queryset_warning(self): |     def test_get_current_queryset_warning(self): | ||||||
|         msg = ( |         msg = ( | ||||||
|             "Prefetch.get_current_queryset() is deprecated. Use " |             "Prefetch.get_current_queryset() is deprecated. Use " | ||||||
| @@ -2011,3 +2013,41 @@ class GetCurrentQuerySetDeprecation(TestCase): | |||||||
|             ) |             ) | ||||||
|         with self.assertWarnsMessage(RemovedInDjango60Warning, msg): |         with self.assertWarnsMessage(RemovedInDjango60Warning, msg): | ||||||
|             self.assertIsNone(Prefetch("authors").get_current_queryset(1)) |             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, []) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user