summaryrefslogtreecommitdiff
path: root/django/db/models/sql
diff options
context:
space:
mode:
authorJosh Smeaton <josh.smeaton@gmail.com>2017-01-17 02:03:15 +1100
committerTim Graham <timograham@gmail.com>2017-01-16 10:03:15 -0500
commit1df89a60c5b7a28d7fda4c9ba7c07f02fd7de0fa (patch)
tree682ee02fb33cc654803d37b46b65dc38f32d506e /django/db/models/sql
parentf2d2f178965584a1ebe666a6621ef82581233fab (diff)
Fixed #25307 -- Fixed QuerySet.annotate() crash with conditional expressions.
Thanks Travis Newport for the tests and Josh Smeaton for contributing to the patch.
Diffstat (limited to 'django/db/models/sql')
-rw-r--r--django/db/models/sql/query.py12
-rw-r--r--django/db/models/sql/where.py11
2 files changed, 22 insertions, 1 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 16ed92a4d4..5f65786373 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -18,6 +18,7 @@ from django.db.models.aggregates import Count
from django.db.models.constants import LOOKUP_SEP
from django.db.models.expressions import Col, Ref
from django.db.models.fields.related_lookups import MultiColSource
+from django.db.models.lookups import Lookup
from django.db.models.query_utils import (
Q, check_rel_lookup_compatibility, refs_expression,
)
@@ -366,11 +367,20 @@ class Query(object):
orig_exprs = annotation.get_source_expressions()
new_exprs = []
for expr in orig_exprs:
+ # FIXME: These conditions are fairly arbitrary. Identify a better
+ # method of having expressions decide which code path they should
+ # take.
if isinstance(expr, Ref):
# Its already a Ref to subquery (see resolve_ref() for
# details)
new_exprs.append(expr)
- elif isinstance(expr, Col):
+ elif isinstance(expr, (WhereNode, Lookup)):
+ # Decompose the subexpressions further. The code here is
+ # copied from the else clause, but this condition must appear
+ # before the contains_aggregate/is_summary condition below.
+ new_expr, col_cnt = self.rewrite_cols(expr, col_cnt)
+ new_exprs.append(new_expr)
+ elif isinstance(expr, Col) or (expr.contains_aggregate and not expr.is_summary):
# Reference to column. Make sure the referenced column
# is selected.
col_cnt += 1
diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
index df44803b8a..bb4e9252b4 100644
--- a/django/db/models/sql/where.py
+++ b/django/db/models/sql/where.py
@@ -118,6 +118,13 @@ class WhereNode(tree.Node):
cols.extend(child.get_group_by_cols())
return cols
+ def get_source_expressions(self):
+ return self.children[:]
+
+ def set_source_expressions(self, children):
+ assert len(children) == len(self.children)
+ self.children = children
+
def relabel_aliases(self, change_map):
"""
Relabels the alias values of any children. 'change_map' is a dictionary
@@ -160,6 +167,10 @@ class WhereNode(tree.Node):
def contains_aggregate(self):
return self._contains_aggregate(self)
+ @property
+ def is_summary(self):
+ return any(child.is_summary for child in self.children)
+
class NothingNode(object):
"""