From e16d0c176e9b89628cdec5e58c418378c4a2436a Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Fri, 29 Dec 2023 01:03:54 -0500 Subject: [PATCH] Fixed #35064 -- Fixed Window(order_by) crash with DecimalFields on SQLite. This avoids cast of Window(order_by) for DecimalFields on SQLite. This was achieved by piggy-backing ExpressionList which already implements a specialized as_sqlite() method to override the inherited behaviour of Func through SQLiteNumericMixin. Refs #31723. Thanks Quoates for the report. --- django/db/models/expressions.py | 17 +++-------------- tests/expressions_window/tests.py | 26 ++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index 41443dc6db..b67a2418d4 100644 --- a/django/db/models/expressions.py +++ b/django/db/models/expressions.py @@ -1267,12 +1267,12 @@ class ExpressionList(Func): 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()) + for expr in self.get_source_expressions(): + group_by_cols.extend(expr.get_group_by_cols()) return group_by_cols -class OrderByList(Func): +class OrderByList(ExpressionList): allowed_default = False template = "ORDER BY %(expressions)s" @@ -1287,17 +1287,6 @@ class OrderByList(Func): ) super().__init__(*expressions, **extra) - def as_sql(self, *args, **kwargs): - if not self.source_expressions: - return "", () - return super().as_sql(*args, **kwargs) - - def get_group_by_cols(self): - group_by_cols = [] - for order_by in self.get_source_expressions(): - group_by_cols.extend(order_by.get_group_by_cols()) - return group_by_cols - @deconstructible(path="django.db.models.ExpressionWrapper") class ExpressionWrapper(SQLiteNumericMixin, Expression): diff --git a/tests/expressions_window/tests.py b/tests/expressions_window/tests.py index fb14e56349..fd674e319b 100644 --- a/tests/expressions_window/tests.py +++ b/tests/expressions_window/tests.py @@ -354,6 +354,29 @@ class WindowFunctionTests(TestCase): transform=lambda row: (row.name, row.bonus, row.department, row.lag), ) + def test_order_by_decimalfield(self): + qs = Employee.objects.annotate( + rank=Window(expression=Rank(), order_by="bonus") + ).order_by("-bonus", "id") + self.assertQuerySetEqual( + qs, + [ + ("Miller", 250.0, 12), + ("Johnson", 200.0, 11), + ("Wilkinson", 150.0, 10), + ("Smith", 137.5, 9), + ("Brown", 132.5, 8), + ("Adams", 125.0, 7), + ("Jones", 112.5, 5), + ("Jenson", 112.5, 5), + ("Johnson", 100.0, 4), + ("Smith", 95.0, 3), + ("Williams", 92.5, 2), + ("Moore", 85.0, 1), + ], + transform=lambda row: (row.name, float(row.bonus), row.rank), + ) + def test_first_value(self): qs = Employee.objects.annotate( first_value=Window( @@ -1934,8 +1957,7 @@ class NonQueryWindowTests(SimpleTestCase): ) self.assertEqual( repr(Window(expression=Avg("salary"), order_by=F("department").asc())), - "", + "", ) def test_window_frame_repr(self):