summaryrefslogtreecommitdiff
path: root/django/db/models/sql/query.py
diff options
context:
space:
mode:
authorAlexandr Tatarinov <tatarinov1997@gmail.com>2020-06-14 21:38:43 +0300
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-07-31 13:19:33 +0200
commitf4ac167119e8897c398527c392ed117326496652 (patch)
tree7df0826447759a792c008286314bc3477405d33d /django/db/models/sql/query.py
parent88af11c58baf0eae2fa947a5f0733906ffe6bb38 (diff)
Fixed #27719 -- Added QuerySet.alias() to allow creating reusable aliases.
QuerySet.alias() allows creating reusable aliases for expressions that don't need to be selected but are used for filtering, ordering, or as a part of complex expressions. Thanks Simon Charette for reviews.
Diffstat (limited to 'django/db/models/sql/query.py')
-rw-r--r--django/db/models/sql/query.py17
1 files changed, 15 insertions, 2 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index b53980a68f..659fa87314 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -1015,11 +1015,14 @@ class Query(BaseExpression):
alias = seen[int_model] = join_info.joins[-1]
return alias or seen[None]
- def add_annotation(self, annotation, alias, is_summary=False):
+ def add_annotation(self, annotation, alias, is_summary=False, select=True):
"""Add a single annotation expression to the Query."""
annotation = annotation.resolve_expression(self, allow_joins=True, reuse=None,
summarize=is_summary)
- self.append_annotation_mask([alias])
+ if select:
+ self.append_annotation_mask([alias])
+ else:
+ self.set_annotation_mask(set(self.annotation_select).difference({alias}))
self.annotations[alias] = annotation
def resolve_expression(self, query, *args, **kwargs):
@@ -1707,6 +1710,11 @@ class Query(BaseExpression):
# which is executed as a wrapped subquery if any of the
# aggregate() elements reference an existing annotation. In
# that case we need to return a Ref to the subquery's annotation.
+ if name not in self.annotation_select:
+ raise FieldError(
+ "Cannot aggregate over the '%s' alias. Use annotate() "
+ "to promote it." % name
+ )
return Ref(name, self.annotation_select[name])
else:
return annotation
@@ -1911,6 +1919,11 @@ class Query(BaseExpression):
# For lookups spanning over relationships, show the error
# from the model on which the lookup failed.
raise
+ elif name in self.annotations:
+ raise FieldError(
+ "Cannot select the '%s' alias. Use annotate() to promote "
+ "it." % name
+ )
else:
names = sorted([
*get_field_names_from_opts(opts), *self.extra,