|
@@ -33,6 +33,7 @@ from django.db.models.utils import (
|
|
|
resolve_callables,
|
|
|
)
|
|
|
from django.utils import timezone
|
|
|
+from django.utils.deprecation import RemovedInDjango60Warning
|
|
|
from django.utils.functional import cached_property, partition
|
|
|
|
|
|
# The maximum number of results to fetch in a get() query.
|
|
@@ -2236,8 +2237,21 @@ class Prefetch:
|
|
|
return to_attr, as_attr
|
|
|
|
|
|
def get_current_queryset(self, level):
|
|
|
- if self.get_current_prefetch_to(level) == self.prefetch_to:
|
|
|
- return self.queryset
|
|
|
+ warnings.warn(
|
|
|
+ "Prefetch.get_current_queryset() is deprecated. Use "
|
|
|
+ "get_current_querysets() instead.",
|
|
|
+ RemovedInDjango60Warning,
|
|
|
+ stacklevel=2,
|
|
|
+ )
|
|
|
+ querysets = self.get_current_querysets(level)
|
|
|
+ return querysets[0] if querysets is not None else None
|
|
|
+
|
|
|
+ def get_current_querysets(self, level):
|
|
|
+ if (
|
|
|
+ self.get_current_prefetch_to(level) == self.prefetch_to
|
|
|
+ and self.queryset is not None
|
|
|
+ ):
|
|
|
+ return [self.queryset]
|
|
|
return None
|
|
|
|
|
|
def __eq__(self, other):
|
|
@@ -2425,9 +2439,9 @@ async def aprefetch_related_objects(model_instances, *related_lookups):
|
|
|
def get_prefetcher(instance, through_attr, to_attr):
|
|
|
"""
|
|
|
For the attribute 'through_attr' on the given instance, find
|
|
|
- an object that has a get_prefetch_queryset().
|
|
|
+ an object that has a get_prefetch_querysets().
|
|
|
Return a 4 tuple containing:
|
|
|
- (the object with get_prefetch_queryset (or None),
|
|
|
+ (the object with get_prefetch_querysets (or None),
|
|
|
the descriptor object representing this relationship (or None),
|
|
|
a boolean that is False if the attribute was not found at all,
|
|
|
a function that takes an instance and returns a boolean that is True if
|
|
@@ -2462,8 +2476,12 @@ def get_prefetcher(instance, through_attr, to_attr):
|
|
|
attr_found = True
|
|
|
if rel_obj_descriptor:
|
|
|
# singly related object, descriptor object has the
|
|
|
- # get_prefetch_queryset() method.
|
|
|
- if hasattr(rel_obj_descriptor, "get_prefetch_queryset"):
|
|
|
+ # get_prefetch_querysets() method.
|
|
|
+ if (
|
|
|
+ hasattr(rel_obj_descriptor, "get_prefetch_querysets")
|
|
|
+ # RemovedInDjango60Warning.
|
|
|
+ or hasattr(rel_obj_descriptor, "get_prefetch_queryset")
|
|
|
+ ):
|
|
|
prefetcher = rel_obj_descriptor
|
|
|
# If to_attr is set, check if the value has already been set,
|
|
|
# which is done with has_to_attr_attribute(). Do not use the
|
|
@@ -2476,7 +2494,11 @@ def get_prefetcher(instance, through_attr, to_attr):
|
|
|
# the attribute on the instance rather than the class to
|
|
|
# support many related managers
|
|
|
rel_obj = getattr(instance, through_attr)
|
|
|
- if hasattr(rel_obj, "get_prefetch_queryset"):
|
|
|
+ if (
|
|
|
+ hasattr(rel_obj, "get_prefetch_querysets")
|
|
|
+ # RemovedInDjango60Warning.
|
|
|
+ or hasattr(rel_obj, "get_prefetch_queryset")
|
|
|
+ ):
|
|
|
prefetcher = rel_obj
|
|
|
if through_attr == to_attr:
|
|
|
|
|
@@ -2497,7 +2519,7 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
|
|
|
Return the prefetched objects along with any additional prefetches that
|
|
|
must be done due to prefetch_related lookups found from default managers.
|
|
|
"""
|
|
|
- # prefetcher must have a method get_prefetch_queryset() which takes a list
|
|
|
+ # prefetcher must have a method get_prefetch_querysets() which takes a list
|
|
|
# of instances, and returns a tuple:
|
|
|
|
|
|
# (queryset of instances of self.model that are related to passed in instances,
|
|
@@ -2510,14 +2532,34 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
|
|
|
# The 'values to be matched' must be hashable as they will be used
|
|
|
# in a dictionary.
|
|
|
|
|
|
- (
|
|
|
- rel_qs,
|
|
|
- rel_obj_attr,
|
|
|
- instance_attr,
|
|
|
- single,
|
|
|
- cache_name,
|
|
|
- is_descriptor,
|
|
|
- ) = prefetcher.get_prefetch_queryset(instances, lookup.get_current_queryset(level))
|
|
|
+ if hasattr(prefetcher, "get_prefetch_querysets"):
|
|
|
+ (
|
|
|
+ rel_qs,
|
|
|
+ rel_obj_attr,
|
|
|
+ instance_attr,
|
|
|
+ single,
|
|
|
+ cache_name,
|
|
|
+ is_descriptor,
|
|
|
+ ) = prefetcher.get_prefetch_querysets(
|
|
|
+ instances, lookup.get_current_querysets(level)
|
|
|
+ )
|
|
|
+ else:
|
|
|
+ warnings.warn(
|
|
|
+ "The usage of get_prefetch_queryset() in prefetch_related_objects() is "
|
|
|
+ "deprecated. Implement get_prefetch_querysets() instead.",
|
|
|
+ RemovedInDjango60Warning,
|
|
|
+ stacklevel=2,
|
|
|
+ )
|
|
|
+ (
|
|
|
+ rel_qs,
|
|
|
+ rel_obj_attr,
|
|
|
+ instance_attr,
|
|
|
+ single,
|
|
|
+ cache_name,
|
|
|
+ is_descriptor,
|
|
|
+ ) = prefetcher.get_prefetch_queryset(
|
|
|
+ instances, lookup.get_current_querysets(level)
|
|
|
+ )
|
|
|
# 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
|