mirror of
https://github.com/django/django.git
synced 2025-10-09 14:59:24 +00:00
Fixed #36426 -- Added support for further iterables in prefetch_related_objects().
Thanks Sarah Boyce for the review.
This commit is contained in:
parent
e059bbec96
commit
e08fa42fa6
@ -2333,8 +2333,8 @@ def normalize_prefetch_lookups(lookups, prefix=None):
|
||||
|
||||
def prefetch_related_objects(model_instances, *related_lookups):
|
||||
"""
|
||||
Populate prefetched object caches for a list of model instances based on
|
||||
the lookups/Prefetch instances given.
|
||||
Populate prefetched object caches for an iterable of model instances based
|
||||
on the lookups/Prefetch instances given.
|
||||
"""
|
||||
if not model_instances:
|
||||
return # nothing to do
|
||||
@ -2402,7 +2402,7 @@ def prefetch_related_objects(model_instances, *related_lookups):
|
||||
# We assume that objects retrieved are homogeneous (which is the
|
||||
# premise of prefetch_related), so what applies to first object
|
||||
# applies to all.
|
||||
first_obj = obj_list[0]
|
||||
first_obj = next(iter(obj_list))
|
||||
to_attr = lookup.get_current_to_attr(level)[0]
|
||||
prefetcher, descriptor, attr_found, is_fetched = get_prefetcher(
|
||||
first_obj, through_attr, to_attr
|
||||
|
@ -4223,8 +4223,9 @@ Prefetches the given lookups on an iterable of model instances. This is useful
|
||||
in code that receives a list of model instances as opposed to a ``QuerySet``;
|
||||
for example, when fetching models from a cache or instantiating them manually.
|
||||
|
||||
Pass an iterable of model instances (must all be of the same class) and the
|
||||
lookups or :class:`Prefetch` objects you want to prefetch for. For example:
|
||||
Pass an iterable of model instances (must all be of the same class and able to
|
||||
be iterated multiple times) and the lookups or :class:`Prefetch` objects you
|
||||
want to prefetch for. For example:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
from collections import deque
|
||||
|
||||
from django.db.models import Prefetch, prefetch_related_objects
|
||||
from django.test import TestCase
|
||||
|
||||
@ -221,3 +223,32 @@ class PrefetchRelatedObjectsTests(TestCase):
|
||||
|
||||
with self.assertNumQueries(0):
|
||||
self.assertCountEqual(book1.authors.all(), [self.author1, self.author2])
|
||||
|
||||
def test_prefetch_related_objects_with_various_iterables(self):
|
||||
book = self.book1
|
||||
|
||||
class MyIterable:
|
||||
def __iter__(self):
|
||||
yield book
|
||||
|
||||
cases = {
|
||||
"set": {book},
|
||||
"tuple": (book,),
|
||||
"dict_values": {"a": book}.values(),
|
||||
"frozenset": frozenset([book]),
|
||||
"deque": deque([book]),
|
||||
"custom iterator": MyIterable(),
|
||||
}
|
||||
for case_type, case in cases.items():
|
||||
with self.subTest(case=case_type):
|
||||
# Clear the prefetch cache.
|
||||
book._prefetched_objects_cache = {}
|
||||
with self.assertNumQueries(1):
|
||||
prefetch_related_objects(case, "authors")
|
||||
with self.assertNumQueries(0):
|
||||
self.assertCountEqual(
|
||||
book.authors.all(), [self.author1, self.author2, self.author3]
|
||||
)
|
||||
|
||||
def test_prefetch_related_objects_empty(self):
|
||||
prefetch_related_objects([], "authors")
|
||||
|
Loading…
x
Reference in New Issue
Block a user