summaryrefslogtreecommitdiff
path: root/django/db/models/sql
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2022-09-22 23:57:06 -0400
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-10-06 09:34:31 +0200
commit04518e310d4552ff7595a34f5a7f93487d78a406 (patch)
tree0cb94a0dfc2b8c63d3da0ceb90d41b048b067695 /django/db/models/sql
parentc58a8acd413ccc992dd30afd98ed900897e1f719 (diff)
Refs #33308 -- Enabled explicit GROUP BY and ORDER BY aliases.
This ensures explicit grouping from using values() before annotating an aggregate function groups by selected aliases if supported. The GROUP BY feature is disabled on Oracle because it doesn't support it.
Diffstat (limited to 'django/db/models/sql')
-rw-r--r--django/db/models/sql/compiler.py23
-rw-r--r--django/db/models/sql/query.py17
2 files changed, 33 insertions, 7 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index f566546307..e4605918d9 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -131,9 +131,12 @@ class SQLCompiler:
# Converts string references to expressions.
for expr in self.query.group_by:
if not hasattr(expr, "as_sql"):
- expressions.append(self.query.resolve_ref(expr))
- else:
- expressions.append(expr)
+ expr = self.query.resolve_ref(expr)
+ if not self.connection.features.allows_group_by_refs and isinstance(
+ expr, Ref
+ ):
+ expr = expr.source
+ expressions.append(expr)
# Note that even if the group_by is set, it is only the minimal
# set to group by. So, we need to add cols in select, order_by, and
# having into the select in any case.
@@ -344,7 +347,13 @@ class SQLCompiler:
if not self.query.standard_ordering:
field = field.copy()
field.reverse_ordering()
- yield field, False
+ if isinstance(field.expression, F) and (
+ annotation := self.query.annotation_select.get(
+ field.expression.name
+ )
+ ):
+ field.expression = Ref(field.expression.name, annotation)
+ yield field, isinstance(field.expression, Ref)
continue
if field == "?": # random
yield OrderBy(Random()), False
@@ -432,6 +441,10 @@ class SQLCompiler:
"""
result = []
seen = set()
+ replacements = {
+ expr: Ref(alias, expr)
+ for alias, expr in self.query.annotation_select.items()
+ }
for expr, is_ref in self._order_by_pairs():
resolved = expr.resolve_expression(self.query, allow_joins=True, reuse=None)
@@ -461,7 +474,7 @@ class SQLCompiler:
q.add_annotation(expr_src, col_name)
self.query.add_select_col(resolved, col_name)
resolved.set_source_expressions([RawSQL(f"{order_by_idx}", ())])
- sql, params = self.compile(resolved)
+ sql, params = self.compile(resolved.replace_expressions(replacements))
# Don't add the same column twice, but the order direction is
# not taken into account so we strip it. When this entire method
# is refactored into expressions, then we can check each part as we
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 61e39b5153..e454a6e868 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -2220,8 +2220,8 @@ class Query(BaseExpression):
primary key, and the query would be equivalent, the optimization
will be made automatically.
"""
- # Column names from JOINs to check collisions with aliases.
if allow_aliases:
+ # Column names from JOINs to check collisions with aliases.
column_names = set()
seen_models = set()
for join in list(self.alias_map.values())[1:]: # Skip base table.
@@ -2231,7 +2231,20 @@ class Query(BaseExpression):
{field.column for field in model._meta.local_concrete_fields}
)
seen_models.add(model)
-
+ if self.values_select:
+ # If grouping by aliases is allowed assign selected values
+ # aliases by moving them to annotations.
+ group_by_annotations = {}
+ values_select = {}
+ for alias, expr in zip(self.values_select, self.select):
+ if isinstance(expr, Col):
+ values_select[alias] = expr
+ else:
+ group_by_annotations[alias] = expr
+ self.annotations = {**group_by_annotations, **self.annotations}
+ self.append_annotation_mask(group_by_annotations)
+ self.select = tuple(values_select.values())
+ self.values_select = tuple(values_select)
group_by = list(self.select)
if self.annotation_select:
for alias, annotation in self.annotation_select.items():