summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2023-11-23 00:09:08 -0500
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-11-23 06:10:24 +0100
commitcf95de9d24c987beff51b54979c02aeef1f98050 (patch)
tree624baa0e4af139eb31a06f7bebfc4e2334007044
parent6d7313bc870b0a37287dc7e3b30b1b5583c9ef0e (diff)
[4.2.x] Fixed #34987 -- Fixed queryset crash when mixing aggregate and window annotations.
Regression in f387d024fc75569d2a4a338bfda76cc2f328f627. Just like `OrderByList` the `ExpressionList` expression used to wrap `Window.partition_by` must implement `get_group_by_cols` to ensure the necessary grouping when mixing window expressions with aggregate annotations is performed against the partition members and not the partition expression itself. This is necessary because while `partition_by` is implemented as a source expression of `Window` it's actually a fragment of the WINDOW expression at the SQL level and thus it should result in a group by its members and not the sum of them. Thanks ElRoberto538 for the report. Backport of e76cc93b0168fa3abbafb9af1ab4535814b751f0 from main
-rw-r--r--django/db/models/expressions.py6
-rw-r--r--docs/releases/4.2.8.txt4
-rw-r--r--tests/expressions_window/tests.py28
3 files changed, 25 insertions, 13 deletions
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 0847eb0931..a0f5145605 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -1223,6 +1223,12 @@ class ExpressionList(Func):
# Casting to numeric is unnecessary.
return self.as_sql(compiler, connection, **extra_context)
+ def get_group_by_cols(self):
+ group_by_cols = []
+ for partition in self.get_source_expressions():
+ group_by_cols.extend(partition.get_group_by_cols())
+ return group_by_cols
+
class OrderByList(Func):
template = "ORDER BY %(expressions)s"
diff --git a/docs/releases/4.2.8.txt b/docs/releases/4.2.8.txt
index 5c2d089b7f..f155e309c3 100644
--- a/docs/releases/4.2.8.txt
+++ b/docs/releases/4.2.8.txt
@@ -16,3 +16,7 @@ Bugfixes
* Fixed a regression in Django 4.2 that caused a crash of
``QuerySet.aggregate()`` with aggregates referencing other aggregates or
window functions through conditional expressions (:ticket:`34975`).
+
+* Fixed a regression in Django 4.2 that caused a crash when annotating a
+ ``QuerySet`` with a ``Window`` expressions composed of a ``partition_by``
+ clause mixing field types and aggregation expressions (:ticket:`34987`).
diff --git a/tests/expressions_window/tests.py b/tests/expressions_window/tests.py
index 3a02a36707..4826ecade8 100644
--- a/tests/expressions_window/tests.py
+++ b/tests/expressions_window/tests.py
@@ -837,23 +837,24 @@ class WindowFunctionTests(TestCase):
max=Window(
expression=Max("salary"),
partition_by=[F("department"), F("hire_date__year")],
- )
+ ),
+ past_department_count=Count("past_departments"),
).order_by("department", "hire_date", "name")
self.assertQuerySetEqual(
qs,
[
- ("Jones", 45000, "Accounting", datetime.date(2005, 11, 1), 45000),
- ("Jenson", 45000, "Accounting", datetime.date(2008, 4, 1), 45000),
- ("Williams", 37000, "Accounting", datetime.date(2009, 6, 1), 37000),
- ("Adams", 50000, "Accounting", datetime.date(2013, 7, 1), 50000),
- ("Wilkinson", 60000, "IT", datetime.date(2011, 3, 1), 60000),
- ("Moore", 34000, "IT", datetime.date(2013, 8, 1), 34000),
- ("Miller", 100000, "Management", datetime.date(2005, 6, 1), 100000),
- ("Johnson", 80000, "Management", datetime.date(2005, 7, 1), 100000),
- ("Smith", 38000, "Marketing", datetime.date(2009, 10, 1), 38000),
- ("Johnson", 40000, "Marketing", datetime.date(2012, 3, 1), 40000),
- ("Smith", 55000, "Sales", datetime.date(2007, 6, 1), 55000),
- ("Brown", 53000, "Sales", datetime.date(2009, 9, 1), 53000),
+ ("Jones", 45000, "Accounting", datetime.date(2005, 11, 1), 45000, 0),
+ ("Jenson", 45000, "Accounting", datetime.date(2008, 4, 1), 45000, 0),
+ ("Williams", 37000, "Accounting", datetime.date(2009, 6, 1), 37000, 0),
+ ("Adams", 50000, "Accounting", datetime.date(2013, 7, 1), 50000, 0),
+ ("Wilkinson", 60000, "IT", datetime.date(2011, 3, 1), 60000, 0),
+ ("Moore", 34000, "IT", datetime.date(2013, 8, 1), 34000, 0),
+ ("Miller", 100000, "Management", datetime.date(2005, 6, 1), 100000, 1),
+ ("Johnson", 80000, "Management", datetime.date(2005, 7, 1), 100000, 0),
+ ("Smith", 38000, "Marketing", datetime.date(2009, 10, 1), 38000, 0),
+ ("Johnson", 40000, "Marketing", datetime.date(2012, 3, 1), 40000, 1),
+ ("Smith", 55000, "Sales", datetime.date(2007, 6, 1), 55000, 0),
+ ("Brown", 53000, "Sales", datetime.date(2009, 9, 1), 53000, 0),
],
transform=lambda row: (
row.name,
@@ -861,6 +862,7 @@ class WindowFunctionTests(TestCase):
row.department,
row.hire_date,
row.max,
+ row.past_department_count,
),
)