From fa352626c2a80bcdcd0fc6492b5fd5130490f05e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Ehrlich?= Date: Thu, 1 Mar 2018 08:55:05 +0100 Subject: [PATCH] Fixed #29172 -- Fixed crash with Window expression in a subquery. --- django/db/models/expressions.py | 6 ++++-- docs/releases/2.0.3.txt | 3 +++ tests/expressions_window/tests.py | 13 +++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index 307ee97db5..4ce869d80a 100644 --- a/django/db/models/expressions.py +++ b/django/db/models/expressions.py @@ -315,8 +315,10 @@ class BaseExpression: def relabeled_clone(self, change_map): clone = self.copy() - clone.set_source_expressions( - [e.relabeled_clone(change_map) for e in self.get_source_expressions()]) + clone.set_source_expressions([ + e.relabeled_clone(change_map) if e is not None else None + for e in self.get_source_expressions() + ]) return clone def copy(self): diff --git a/docs/releases/2.0.3.txt b/docs/releases/2.0.3.txt index 42020a6923..f4f30b5a30 100644 --- a/docs/releases/2.0.3.txt +++ b/docs/releases/2.0.3.txt @@ -25,3 +25,6 @@ Bugfixes * Fixed a regression where a ``When()`` expression with a list argument crashes (:ticket:`29166`). + +* Fixed crash when using a ``Window()`` expression in a subquery + (:ticket:`29172`). diff --git a/tests/expressions_window/tests.py b/tests/expressions_window/tests.py index e61516b4b6..7ade53f429 100644 --- a/tests/expressions_window/tests.py +++ b/tests/expressions_window/tests.py @@ -650,6 +650,19 @@ class WindowFunctionTests(TestCase): salary=Window(expression=Sum(Value(10000), order_by=F('pk').asc())), ) + def test_window_expression_within_subquery(self): + subquery_qs = Employee.objects.annotate( + highest=Window(FirstValue('id'), partition_by=F('department'), order_by=F('salary').desc()) + ).values('highest') + highest_salary = Employee.objects.filter(pk__in=subquery_qs) + self.assertSequenceEqual(highest_salary.values('department', 'salary'), [ + {'department': 'Accounting', 'salary': 50000}, + {'department': 'Sales', 'salary': 55000}, + {'department': 'Marketing', 'salary': 40000}, + {'department': 'IT', 'salary': 60000}, + {'department': 'Management', 'salary': 100000} + ]) + def test_invalid_start_value_range(self): msg = "start argument must be a negative integer, zero, or None, but got '3'." with self.assertRaisesMessage(ValueError, msg):