mirror of
https://github.com/django/django.git
synced 2025-10-10 07:19:11 +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):
|
def prefetch_related_objects(model_instances, *related_lookups):
|
||||||
"""
|
"""
|
||||||
Populate prefetched object caches for a list of model instances based on
|
Populate prefetched object caches for an iterable of model instances based
|
||||||
the lookups/Prefetch instances given.
|
on the lookups/Prefetch instances given.
|
||||||
"""
|
"""
|
||||||
if not model_instances:
|
if not model_instances:
|
||||||
return # nothing to do
|
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
|
# We assume that objects retrieved are homogeneous (which is the
|
||||||
# premise of prefetch_related), so what applies to first object
|
# premise of prefetch_related), so what applies to first object
|
||||||
# applies to all.
|
# applies to all.
|
||||||
first_obj = obj_list[0]
|
first_obj = next(iter(obj_list))
|
||||||
to_attr = lookup.get_current_to_attr(level)[0]
|
to_attr = lookup.get_current_to_attr(level)[0]
|
||||||
prefetcher, descriptor, attr_found, is_fetched = get_prefetcher(
|
prefetcher, descriptor, attr_found, is_fetched = get_prefetcher(
|
||||||
first_obj, through_attr, to_attr
|
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``;
|
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.
|
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
|
Pass an iterable of model instances (must all be of the same class and able to
|
||||||
lookups or :class:`Prefetch` objects you want to prefetch for. For example:
|
be iterated multiple times) and the lookups or :class:`Prefetch` objects you
|
||||||
|
want to prefetch for. For example:
|
||||||
|
|
||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from collections import deque
|
||||||
|
|
||||||
from django.db.models import Prefetch, prefetch_related_objects
|
from django.db.models import Prefetch, prefetch_related_objects
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
@ -221,3 +223,32 @@ class PrefetchRelatedObjectsTests(TestCase):
|
|||||||
|
|
||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
self.assertCountEqual(book1.authors.all(), [self.author1, self.author2])
|
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