1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
From: Hannes Ljungberg <hannes.ljungberg@gmail.com>
Date: Wed, 26 May 2021 22:09:15 +0200
Subject: Refs #32786 -- Made Query.clear_ordering() not to cause side effects
by default.
(cherry picked from commit 053141d31fe5aef1c255a1be183383860e0ccce9)
---
django/db/models/query.py | 8 ++++----
django/db/models/sql/compiler.py | 2 +-
django/db/models/sql/query.py | 29 ++++++++++++++++-------------
3 files changed, 21 insertions(+), 18 deletions(-)
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 02c1b314355c..5ba0a10956c6 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -659,7 +659,7 @@ class QuerySet:
"Cannot change a query once a slice has been taken."
obj = self._chain()
obj.query.set_limits(high=1)
- obj.query.clear_ordering(force_empty=True)
+ obj.query.clear_ordering(force=True)
obj.query.add_ordering(*order_by)
return obj.get()
@@ -739,7 +739,7 @@ class QuerySet:
# Disable non-supported fields.
del_query.query.select_for_update = False
del_query.query.select_related = False
- del_query.query.clear_ordering(force_empty=True)
+ del_query.query.clear_ordering(force=True)
collector = Collector(using=del_query.db)
collector.collect(del_query)
@@ -988,7 +988,7 @@ class QuerySet:
# Clone the query to inherit the select list and everything
clone = self._chain()
# Clear limits and ordering so they can be reapplied
- clone.query.clear_ordering(True)
+ clone.query.clear_ordering(force=True)
clone.query.clear_limits()
clone.query.combined_queries = (self.query,) + tuple(qs.query for qs in other_qs)
clone.query.combinator = combinator
@@ -1145,7 +1145,7 @@ class QuerySet:
assert not self.query.is_sliced, \
"Cannot reorder a query once a slice has been taken."
obj = self._chain()
- obj.query.clear_ordering(force_empty=False)
+ obj.query.clear_ordering(force=True, clear_default=False)
obj.query.add_ordering(*field_names)
return obj
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 6254946bc43f..a55e1d3c363c 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -1587,7 +1587,7 @@ class SQLUpdateCompiler(SQLCompiler):
return
query = self.query.chain(klass=Query)
query.select_related = False
- query.clear_ordering(True)
+ query.clear_ordering(force=True)
query.extra = {}
query.select = []
query.add_fields([query.get_meta().pk.name])
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 230b6fa8610e..db52a4976951 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -461,11 +461,10 @@ class Query(BaseExpression):
inner_query.select_for_update = False
inner_query.select_related = False
inner_query.set_annotation_mask(self.annotation_select)
- if not self.is_sliced and not self.distinct_fields:
- # Queries with distinct_fields need ordering and when a limit
- # is applied we must take the slice from the ordered query.
- # Otherwise no need for ordering.
- inner_query.clear_ordering(True)
+ # Queries with distinct_fields need ordering and when a limit is
+ # applied we must take the slice from the ordered query. Otherwise
+ # no need for ordering.
+ inner_query.clear_ordering(force=False)
if not inner_query.distinct:
# If the inner query uses default select and it has some
# aggregate annotations, then we must make sure the inner
@@ -505,7 +504,7 @@ class Query(BaseExpression):
self.default_cols = False
self.extra = {}
- outer_query.clear_ordering(True)
+ outer_query.clear_ordering(force=True)
outer_query.clear_limits()
outer_query.select_for_update = False
outer_query.select_related = False
@@ -548,7 +547,7 @@ class Query(BaseExpression):
combined_query.exists(using, limit=limit_combined)
for combined_query in q.combined_queries
)
- q.clear_ordering(True)
+ q.clear_ordering(force=True)
if limit:
q.set_limits(high=1)
q.add_extra({'a': 1}, None, None, None, None, None)
@@ -1077,7 +1076,7 @@ class Query(BaseExpression):
if (self.low_mark == 0 and self.high_mark is None and
not self.distinct_fields and
not self.select_for_update):
- clone.clear_ordering(True)
+ clone.clear_ordering(force=True)
clone.where.resolve_expression(query, *args, **kwargs)
for key, value in clone.annotations.items():
resolved = value.resolve_expression(query, *args, **kwargs)
@@ -1818,7 +1817,7 @@ class Query(BaseExpression):
query = Query(self.model)
query._filtered_relations = self._filtered_relations
query.add_filter(filter_expr)
- query.clear_ordering(True)
+ query.clear_ordering(force=True)
# Try to have as simple as possible subquery -> trim leading joins from
# the subquery.
trimmed_prefix, contains_louter = query.trim_start(names_with_path)
@@ -2028,14 +2027,18 @@ class Query(BaseExpression):
else:
self.default_ordering = False
- def clear_ordering(self, force_empty):
+ def clear_ordering(self, force=False, clear_default=True):
"""
- Remove any ordering settings. If 'force_empty' is True, there will be
- no ordering in the resulting query (not even the model's default).
+ Remove any ordering settings if the current query allows it without
+ side effects, set 'force' to True to clear the ordering regardless.
+ If 'clear_default' is True, there will be no ordering in the resulting
+ query (not even the model's default).
"""
+ if not force and (self.is_sliced or self.distinct_fields or self.select_for_update):
+ return
self.order_by = ()
self.extra_order_by = ()
- if force_empty:
+ if clear_default:
self.default_ordering = False
def set_group_by(self, allow_aliases=True):
|