Refs #20880 -- Removed non-cloning logic from QuerySet._clone().
This commit is contained in:
parent
0baea920c8
commit
66933a6619
|
@ -261,7 +261,7 @@ class QuerySet:
|
||||||
return self._result_cache[k]
|
return self._result_cache[k]
|
||||||
|
|
||||||
if isinstance(k, slice):
|
if isinstance(k, slice):
|
||||||
qs = self._clone()
|
qs = self._chain()
|
||||||
if k.start is not None:
|
if k.start is not None:
|
||||||
start = int(k.start)
|
start = int(k.start)
|
||||||
else:
|
else:
|
||||||
|
@ -273,7 +273,7 @@ class QuerySet:
|
||||||
qs.query.set_limits(start, stop)
|
qs.query.set_limits(start, stop)
|
||||||
return list(qs)[::k.step] if k.step else qs
|
return list(qs)[::k.step] if k.step else qs
|
||||||
|
|
||||||
qs = self._clone()
|
qs = self._chain()
|
||||||
qs.query.set_limits(k, k + 1)
|
qs.query.set_limits(k, k + 1)
|
||||||
qs._fetch_all()
|
qs._fetch_all()
|
||||||
return qs._result_cache[0]
|
return qs._result_cache[0]
|
||||||
|
@ -284,7 +284,7 @@ class QuerySet:
|
||||||
return other
|
return other
|
||||||
if isinstance(self, EmptyQuerySet):
|
if isinstance(self, EmptyQuerySet):
|
||||||
return self
|
return self
|
||||||
combined = self._clone()
|
combined = self._chain()
|
||||||
combined._merge_known_related_objects(other)
|
combined._merge_known_related_objects(other)
|
||||||
combined.query.combine(other.query, sql.AND)
|
combined.query.combine(other.query, sql.AND)
|
||||||
return combined
|
return combined
|
||||||
|
@ -295,7 +295,7 @@ class QuerySet:
|
||||||
return other
|
return other
|
||||||
if isinstance(other, EmptyQuerySet):
|
if isinstance(other, EmptyQuerySet):
|
||||||
return self
|
return self
|
||||||
combined = self._clone()
|
combined = self._chain()
|
||||||
combined._merge_known_related_objects(other)
|
combined._merge_known_related_objects(other)
|
||||||
combined.query.combine(other.query, sql.OR)
|
combined.query.combine(other.query, sql.OR)
|
||||||
return combined
|
return combined
|
||||||
|
@ -535,7 +535,7 @@ class QuerySet:
|
||||||
"field_name parameter or 'get_latest_by' in the model"
|
"field_name parameter or 'get_latest_by' in the model"
|
||||||
assert self.query.can_filter(), \
|
assert self.query.can_filter(), \
|
||||||
"Cannot change a query once a slice has been taken."
|
"Cannot change a query once a slice has been taken."
|
||||||
obj = self._clone()
|
obj = self._chain()
|
||||||
obj.query.set_limits(high=1)
|
obj.query.set_limits(high=1)
|
||||||
obj.query.clear_ordering(force_empty=True)
|
obj.query.clear_ordering(force_empty=True)
|
||||||
obj.query.add_ordering('%s%s' % (direction, order_by))
|
obj.query.add_ordering('%s%s' % (direction, order_by))
|
||||||
|
@ -582,7 +582,7 @@ class QuerySet:
|
||||||
else:
|
else:
|
||||||
qs = self.filter(**{filter_key: id_list}).order_by()
|
qs = self.filter(**{filter_key: id_list}).order_by()
|
||||||
else:
|
else:
|
||||||
qs = self._clone()
|
qs = self._chain()
|
||||||
return {getattr(obj, field_name): obj for obj in qs}
|
return {getattr(obj, field_name): obj for obj in qs}
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
|
@ -593,7 +593,7 @@ class QuerySet:
|
||||||
if self._fields is not None:
|
if self._fields is not None:
|
||||||
raise TypeError("Cannot call delete() after .values() or .values_list()")
|
raise TypeError("Cannot call delete() after .values() or .values_list()")
|
||||||
|
|
||||||
del_query = self._clone()
|
del_query = self._chain()
|
||||||
|
|
||||||
# The delete is actually 2 queries - one to find related objects,
|
# The delete is actually 2 queries - one to find related objects,
|
||||||
# and one to delete. Make sure that the discovery of related
|
# and one to delete. Make sure that the discovery of related
|
||||||
|
@ -678,7 +678,7 @@ class QuerySet:
|
||||||
return RawQuerySet(raw_query, model=self.model, params=params, translations=translations, using=using)
|
return RawQuerySet(raw_query, model=self.model, params=params, translations=translations, using=using)
|
||||||
|
|
||||||
def _values(self, *fields, **expressions):
|
def _values(self, *fields, **expressions):
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
if expressions:
|
if expressions:
|
||||||
clone = clone.annotate(**expressions)
|
clone = clone.annotate(**expressions)
|
||||||
clone._fields = fields
|
clone._fields = fields
|
||||||
|
@ -748,7 +748,7 @@ class QuerySet:
|
||||||
|
|
||||||
def none(self):
|
def none(self):
|
||||||
"""Return an empty QuerySet."""
|
"""Return an empty QuerySet."""
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
clone.query.set_empty()
|
clone.query.set_empty()
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
|
@ -761,7 +761,7 @@ class QuerySet:
|
||||||
Return a new QuerySet that is a copy of the current one. This allows a
|
Return a new QuerySet that is a copy of the current one. This allows a
|
||||||
QuerySet to proxy for a model manager in some cases.
|
QuerySet to proxy for a model manager in some cases.
|
||||||
"""
|
"""
|
||||||
return self._clone()
|
return self._chain()
|
||||||
|
|
||||||
def filter(self, *args, **kwargs):
|
def filter(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -782,7 +782,7 @@ class QuerySet:
|
||||||
assert self.query.can_filter(), \
|
assert self.query.can_filter(), \
|
||||||
"Cannot filter a query once a slice has been taken."
|
"Cannot filter a query once a slice has been taken."
|
||||||
|
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
if negate:
|
if negate:
|
||||||
clone.query.add_q(~Q(*args, **kwargs))
|
clone.query.add_q(~Q(*args, **kwargs))
|
||||||
else:
|
else:
|
||||||
|
@ -800,7 +800,7 @@ class QuerySet:
|
||||||
and usually it will be more natural to use other methods.
|
and usually it will be more natural to use other methods.
|
||||||
"""
|
"""
|
||||||
if isinstance(filter_obj, Q):
|
if isinstance(filter_obj, Q):
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
clone.query.add_q(filter_obj)
|
clone.query.add_q(filter_obj)
|
||||||
return clone
|
return clone
|
||||||
else:
|
else:
|
||||||
|
@ -808,7 +808,7 @@ class QuerySet:
|
||||||
|
|
||||||
def _combinator_query(self, combinator, *other_qs, all=False):
|
def _combinator_query(self, combinator, *other_qs, all=False):
|
||||||
# Clone the query to inherit the select list and everything
|
# Clone the query to inherit the select list and everything
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
# Clear limits and ordering so they can be reapplied
|
# Clear limits and ordering so they can be reapplied
|
||||||
clone.query.clear_ordering(True)
|
clone.query.clear_ordering(True)
|
||||||
clone.query.clear_limits()
|
clone.query.clear_limits()
|
||||||
|
@ -846,7 +846,7 @@ class QuerySet:
|
||||||
"""
|
"""
|
||||||
if nowait and skip_locked:
|
if nowait and skip_locked:
|
||||||
raise ValueError('The nowait option cannot be used with skip_locked.')
|
raise ValueError('The nowait option cannot be used with skip_locked.')
|
||||||
obj = self._clone()
|
obj = self._chain()
|
||||||
obj._for_write = True
|
obj._for_write = True
|
||||||
obj.query.select_for_update = True
|
obj.query.select_for_update = True
|
||||||
obj.query.select_for_update_nowait = nowait
|
obj.query.select_for_update_nowait = nowait
|
||||||
|
@ -867,7 +867,7 @@ class QuerySet:
|
||||||
if self._fields is not None:
|
if self._fields is not None:
|
||||||
raise TypeError("Cannot call select_related() after .values() or .values_list()")
|
raise TypeError("Cannot call select_related() after .values() or .values_list()")
|
||||||
|
|
||||||
obj = self._clone()
|
obj = self._chain()
|
||||||
if fields == (None,):
|
if fields == (None,):
|
||||||
obj.query.select_related = False
|
obj.query.select_related = False
|
||||||
elif fields:
|
elif fields:
|
||||||
|
@ -885,7 +885,7 @@ class QuerySet:
|
||||||
When prefetch_related() is called more than once, append to the list of
|
When prefetch_related() is called more than once, append to the list of
|
||||||
prefetch lookups. If prefetch_related(None) is called, clear the list.
|
prefetch lookups. If prefetch_related(None) is called, clear the list.
|
||||||
"""
|
"""
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
if lookups == (None,):
|
if lookups == (None,):
|
||||||
clone._prefetch_related_lookups = ()
|
clone._prefetch_related_lookups = ()
|
||||||
else:
|
else:
|
||||||
|
@ -911,7 +911,7 @@ class QuerySet:
|
||||||
annotations[arg.default_alias] = arg
|
annotations[arg.default_alias] = arg
|
||||||
annotations.update(kwargs)
|
annotations.update(kwargs)
|
||||||
|
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
names = self._fields
|
names = self._fields
|
||||||
if names is None:
|
if names is None:
|
||||||
names = {f.name for f in self.model._meta.get_fields()}
|
names = {f.name for f in self.model._meta.get_fields()}
|
||||||
|
@ -936,7 +936,7 @@ class QuerySet:
|
||||||
"""Return a new QuerySet instance with the ordering changed."""
|
"""Return a new QuerySet instance with the ordering changed."""
|
||||||
assert self.query.can_filter(), \
|
assert self.query.can_filter(), \
|
||||||
"Cannot reorder a query once a slice has been taken."
|
"Cannot reorder a query once a slice has been taken."
|
||||||
obj = self._clone()
|
obj = self._chain()
|
||||||
obj.query.clear_ordering(force_empty=False)
|
obj.query.clear_ordering(force_empty=False)
|
||||||
obj.query.add_ordering(*field_names)
|
obj.query.add_ordering(*field_names)
|
||||||
return obj
|
return obj
|
||||||
|
@ -947,7 +947,7 @@ class QuerySet:
|
||||||
"""
|
"""
|
||||||
assert self.query.can_filter(), \
|
assert self.query.can_filter(), \
|
||||||
"Cannot create distinct fields once a slice has been taken."
|
"Cannot create distinct fields once a slice has been taken."
|
||||||
obj = self._clone()
|
obj = self._chain()
|
||||||
obj.query.add_distinct_fields(*field_names)
|
obj.query.add_distinct_fields(*field_names)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
@ -956,7 +956,7 @@ class QuerySet:
|
||||||
"""Add extra SQL fragments to the query."""
|
"""Add extra SQL fragments to the query."""
|
||||||
assert self.query.can_filter(), \
|
assert self.query.can_filter(), \
|
||||||
"Cannot change a query once a slice has been taken"
|
"Cannot change a query once a slice has been taken"
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
clone.query.add_extra(select, select_params, where, params, tables, order_by)
|
clone.query.add_extra(select, select_params, where, params, tables, order_by)
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
|
@ -964,7 +964,7 @@ class QuerySet:
|
||||||
"""Reverse the ordering of the QuerySet."""
|
"""Reverse the ordering of the QuerySet."""
|
||||||
if not self.query.can_filter():
|
if not self.query.can_filter():
|
||||||
raise TypeError('Cannot reverse a query once a slice has been taken.')
|
raise TypeError('Cannot reverse a query once a slice has been taken.')
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
clone.query.standard_ordering = not clone.query.standard_ordering
|
clone.query.standard_ordering = not clone.query.standard_ordering
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
|
@ -977,7 +977,7 @@ class QuerySet:
|
||||||
"""
|
"""
|
||||||
if self._fields is not None:
|
if self._fields is not None:
|
||||||
raise TypeError("Cannot call defer() after .values() or .values_list()")
|
raise TypeError("Cannot call defer() after .values() or .values_list()")
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
if fields == (None,):
|
if fields == (None,):
|
||||||
clone.query.clear_deferred_loading()
|
clone.query.clear_deferred_loading()
|
||||||
else:
|
else:
|
||||||
|
@ -996,13 +996,13 @@ class QuerySet:
|
||||||
# Can only pass None to defer(), not only(), as the rest option.
|
# Can only pass None to defer(), not only(), as the rest option.
|
||||||
# That won't stop people trying to do this, so let's be explicit.
|
# That won't stop people trying to do this, so let's be explicit.
|
||||||
raise TypeError("Cannot pass None as an argument to only().")
|
raise TypeError("Cannot pass None as an argument to only().")
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
clone.query.add_immediate_loading(fields)
|
clone.query.add_immediate_loading(fields)
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
def using(self, alias):
|
def using(self, alias):
|
||||||
"""Select which database this QuerySet should execute against."""
|
"""Select which database this QuerySet should execute against."""
|
||||||
clone = self._clone()
|
clone = self._chain()
|
||||||
clone._db = alias
|
clone._db = alias
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
|
@ -1070,19 +1070,31 @@ class QuerySet:
|
||||||
self._insert(item, fields=fields, using=self.db)
|
self._insert(item, fields=fields, using=self.db)
|
||||||
return inserted_ids
|
return inserted_ids
|
||||||
|
|
||||||
def _clone(self, **kwargs):
|
def _chain(self, **kwargs):
|
||||||
query = self.query.clone()
|
"""
|
||||||
if self._sticky_filter:
|
Return a copy of the current QuerySet that's ready for another
|
||||||
query.filter_is_sticky = True
|
operation.
|
||||||
clone = self.__class__(model=self.model, query=query, using=self._db, hints=self._hints)
|
"""
|
||||||
clone._for_write = self._for_write
|
obj = self._clone()
|
||||||
clone._prefetch_related_lookups = self._prefetch_related_lookups
|
if obj._sticky_filter:
|
||||||
clone._known_related_objects = self._known_related_objects
|
obj.query.filter_is_sticky = True
|
||||||
clone._iterable_class = self._iterable_class
|
obj._sticky_filter = False
|
||||||
clone._fields = self._fields
|
obj.__dict__.update(kwargs)
|
||||||
|
return obj
|
||||||
|
|
||||||
clone.__dict__.update(kwargs)
|
def _clone(self):
|
||||||
return clone
|
"""
|
||||||
|
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._sticky_filter = self._sticky_filter
|
||||||
|
c._for_write = self._for_write
|
||||||
|
c._prefetch_related_lookups = self._prefetch_related_lookups[:]
|
||||||
|
c._known_related_objects = self._known_related_objects
|
||||||
|
c._iterable_class = self._iterable_class
|
||||||
|
c._fields = self._fields
|
||||||
|
return c
|
||||||
|
|
||||||
def _fetch_all(self):
|
def _fetch_all(self):
|
||||||
if self._result_cache is None:
|
if self._result_cache is None:
|
||||||
|
@ -1304,7 +1316,7 @@ class Prefetch:
|
||||||
obj_dict = self.__dict__.copy()
|
obj_dict = self.__dict__.copy()
|
||||||
if self.queryset is not None:
|
if self.queryset is not None:
|
||||||
# Prevent the QuerySet from being evaluated
|
# Prevent the QuerySet from being evaluated
|
||||||
obj_dict['queryset'] = self.queryset._clone(
|
obj_dict['queryset'] = self.queryset._chain(
|
||||||
_result_cache=[],
|
_result_cache=[],
|
||||||
_prefetch_done=True,
|
_prefetch_done=True,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue