Refs #20880 -- Removed non-cloning logic from Query.clone().
This commit is contained in:
parent
66933a6619
commit
6155bc4a51
|
@ -335,7 +335,7 @@ class QuerySet:
|
|||
raise TypeError("Complex aggregates require an alias")
|
||||
kwargs[arg.default_alias] = arg
|
||||
|
||||
query = self.query.clone()
|
||||
query = self.query.chain()
|
||||
for (alias, aggregate_expr) in kwargs.items():
|
||||
query.add_annotation(aggregate_expr, alias, is_summary=True)
|
||||
if not query.annotations[alias].contains_aggregate:
|
||||
|
@ -632,7 +632,7 @@ class QuerySet:
|
|||
assert self.query.can_filter(), \
|
||||
"Cannot update a query once a slice has been taken."
|
||||
self._for_write = True
|
||||
query = self.query.clone(sql.UpdateQuery)
|
||||
query = self.query.chain(sql.UpdateQuery)
|
||||
query.add_update_values(kwargs)
|
||||
# Clear any annotations so that they won't be present in subqueries.
|
||||
query._annotations = None
|
||||
|
@ -651,7 +651,7 @@ class QuerySet:
|
|||
"""
|
||||
assert self.query.can_filter(), \
|
||||
"Cannot update a query once a slice has been taken."
|
||||
query = self.query.clone(sql.UpdateQuery)
|
||||
query = self.query.chain(sql.UpdateQuery)
|
||||
query.add_update_fields(values)
|
||||
self._result_cache = None
|
||||
return query.get_compiler(self.db).execute_sql(CURSOR)
|
||||
|
@ -1087,7 +1087,7 @@ class QuerySet:
|
|||
Return a copy of the current QuerySet. A lightweight alternative
|
||||
to deepcopy().
|
||||
"""
|
||||
c = self.__class__(model=self.model, query=self.query.clone(), using=self._db, hints=self._hints)
|
||||
c = self.__class__(model=self.model, query=self.query.chain(), using=self._db, hints=self._hints)
|
||||
c._sticky_filter = self._sticky_filter
|
||||
c._for_write = self._for_write
|
||||
c._prefetch_related_lookups = self._prefetch_related_lookups[:]
|
||||
|
@ -1267,7 +1267,7 @@ class RawQuerySet:
|
|||
"""Select the database this RawQuerySet should execute against."""
|
||||
return RawQuerySet(
|
||||
self.raw_query, model=self.model,
|
||||
query=self.query.clone(using=alias),
|
||||
query=self.query.chain(using=alias),
|
||||
params=self.params, translations=self.translations,
|
||||
using=alias,
|
||||
)
|
||||
|
|
|
@ -1334,7 +1334,7 @@ class SQLUpdateCompiler(SQLCompiler):
|
|||
count = self.query.count_active_tables()
|
||||
if not self.query.related_updates and count == 1:
|
||||
return
|
||||
query = self.query.clone(klass=Query)
|
||||
query = self.query.chain(klass=Query)
|
||||
query.select_related = False
|
||||
query.clear_ordering(True)
|
||||
query._extra = {}
|
||||
|
|
|
@ -7,6 +7,7 @@ databases). The abstraction barrier only works one way: this module has to know
|
|||
all about the internals of models in order to get the information it needs.
|
||||
"""
|
||||
from collections import Counter, Iterator, Mapping, OrderedDict
|
||||
from contextlib import suppress
|
||||
from itertools import chain, count, product
|
||||
from string import ascii_uppercase
|
||||
|
||||
|
@ -58,6 +59,9 @@ class RawQuery:
|
|||
self.extra_select = {}
|
||||
self.annotation_select = {}
|
||||
|
||||
def chain(self, using):
|
||||
return self.clone(using)
|
||||
|
||||
def clone(self, using):
|
||||
return RawQuery(self.sql, using, params=self.params)
|
||||
|
||||
|
@ -262,35 +266,21 @@ class Query:
|
|||
"""
|
||||
return self.model._meta
|
||||
|
||||
def clone(self, klass=None, **kwargs):
|
||||
def clone(self):
|
||||
"""
|
||||
Create a copy of the current instance. The 'kwargs' parameter can be
|
||||
used by clients to update attributes after copying has taken place.
|
||||
Return a copy of the current Query. A lightweight alternative to
|
||||
to deepcopy().
|
||||
"""
|
||||
obj = Empty()
|
||||
obj.__class__ = klass or self.__class__
|
||||
obj.model = self.model
|
||||
obj.__class__ = self.__class__
|
||||
# Copy references to everything.
|
||||
obj.__dict__ = self.__dict__.copy()
|
||||
# Clone attributes that can't use shallow copy.
|
||||
obj.alias_refcount = self.alias_refcount.copy()
|
||||
obj.alias_map = self.alias_map.copy()
|
||||
obj.external_aliases = self.external_aliases.copy()
|
||||
obj.table_map = self.table_map.copy()
|
||||
obj.default_cols = self.default_cols
|
||||
obj.default_ordering = self.default_ordering
|
||||
obj.standard_ordering = self.standard_ordering
|
||||
obj.select = self.select
|
||||
obj.where = self.where.clone()
|
||||
obj.where_class = self.where_class
|
||||
obj.group_by = self.group_by
|
||||
obj.order_by = self.order_by
|
||||
obj.low_mark, obj.high_mark = self.low_mark, self.high_mark
|
||||
obj.distinct = self.distinct
|
||||
obj.distinct_fields = self.distinct_fields
|
||||
obj.select_for_update = self.select_for_update
|
||||
obj.select_for_update_nowait = self.select_for_update_nowait
|
||||
obj.select_for_update_skip_locked = self.select_for_update_skip_locked
|
||||
obj.select_for_update_of = self.select_for_update_of
|
||||
obj.select_related = self.select_related
|
||||
obj.values_select = self.values_select
|
||||
obj._annotations = self._annotations.copy() if self._annotations is not None else None
|
||||
if self.annotation_select_mask is None:
|
||||
obj.annotation_select_mask = None
|
||||
|
@ -302,10 +292,6 @@ class Query:
|
|||
# It will get re-populated in the cloned queryset the next time it's
|
||||
# used.
|
||||
obj._annotation_select_cache = None
|
||||
obj.max_depth = self.max_depth
|
||||
obj.combinator = self.combinator
|
||||
obj.combinator_all = self.combinator_all
|
||||
obj.combined_queries = self.combined_queries
|
||||
obj._extra = self._extra.copy() if self._extra is not None else None
|
||||
if self.extra_select_mask is None:
|
||||
obj.extra_select_mask = None
|
||||
|
@ -315,21 +301,25 @@ class Query:
|
|||
obj._extra_select_cache = None
|
||||
else:
|
||||
obj._extra_select_cache = self._extra_select_cache.copy()
|
||||
obj.extra_tables = self.extra_tables
|
||||
obj.extra_order_by = self.extra_order_by
|
||||
obj.deferred_loading = self.deferred_loading
|
||||
if self.filter_is_sticky and self.used_aliases:
|
||||
obj.used_aliases = self.used_aliases.copy()
|
||||
else:
|
||||
obj.used_aliases = set()
|
||||
obj.filter_is_sticky = False
|
||||
obj.subquery = self.subquery
|
||||
if 'alias_prefix' in self.__dict__:
|
||||
obj.alias_prefix = self.alias_prefix
|
||||
if 'subq_aliases' in self.__dict__:
|
||||
obj.subq_aliases = self.subq_aliases.copy()
|
||||
obj.used_aliases = self.used_aliases.copy()
|
||||
# Clear the cached_property
|
||||
with suppress(AttributeError):
|
||||
del obj.base_table
|
||||
return obj
|
||||
|
||||
obj.__dict__.update(kwargs)
|
||||
def chain(self, klass=None):
|
||||
"""
|
||||
Return a copy of the current Query that's ready for another operation.
|
||||
The klass argument changes the type of the Query, e.g. UpdateQuery.
|
||||
"""
|
||||
obj = self.clone()
|
||||
if klass and obj.__class__ != klass:
|
||||
obj.__class__ = klass
|
||||
if not obj.filter_is_sticky:
|
||||
obj.used_aliases = set()
|
||||
obj.filter_is_sticky = False
|
||||
if hasattr(obj, '_setup_query'):
|
||||
obj._setup_query()
|
||||
return obj
|
||||
|
|
|
@ -87,16 +87,17 @@ class UpdateQuery(Query):
|
|||
|
||||
def _setup_query(self):
|
||||
"""
|
||||
Run on initialization and after cloning. Any attributes that would
|
||||
normally be set in __init__ should go in here, instead, so that they
|
||||
are also set up after a clone() call.
|
||||
Run on initialization and at the end of chaining. Any attributes that
|
||||
would normally be set in __init__() should go here instead.
|
||||
"""
|
||||
self.values = []
|
||||
self.related_ids = None
|
||||
self.related_updates = {}
|
||||
|
||||
def clone(self, klass=None, **kwargs):
|
||||
return super().clone(klass, related_updates=self.related_updates.copy(), **kwargs)
|
||||
def clone(self):
|
||||
obj = super().clone()
|
||||
obj.related_updates = self.related_updates.copy()
|
||||
return obj
|
||||
|
||||
def update_batch(self, pk_list, values, using):
|
||||
self.add_update_values(values)
|
||||
|
|
Loading…
Reference in New Issue