[2.2.x] Fixed #30332 -- Fixed crash of ordering by expressions with params in ArrayAgg and StringAgg.
Backport of d0315584b5
from master.
This commit is contained in:
parent
9da25fb832
commit
268ed9cd8a
|
@ -21,13 +21,17 @@ class OrderableAggMixin:
|
||||||
|
|
||||||
def as_sql(self, compiler, connection):
|
def as_sql(self, compiler, connection):
|
||||||
if self.ordering:
|
if self.ordering:
|
||||||
self.extra['ordering'] = 'ORDER BY ' + ', '.join((
|
ordering_params = []
|
||||||
ordering_element.as_sql(compiler, connection)[0]
|
ordering_expr_sql = []
|
||||||
for ordering_element in self.ordering
|
for expr in self.ordering:
|
||||||
|
expr_sql, expr_params = expr.as_sql(compiler, connection)
|
||||||
|
ordering_expr_sql.append(expr_sql)
|
||||||
|
ordering_params.extend(expr_params)
|
||||||
|
sql, sql_params = super().as_sql(compiler, connection, ordering=(
|
||||||
|
'ORDER BY ' + ', '.join(ordering_expr_sql)
|
||||||
))
|
))
|
||||||
else:
|
return sql, sql_params + ordering_params
|
||||||
self.extra['ordering'] = ''
|
return super().as_sql(compiler, connection, ordering='')
|
||||||
return super().as_sql(compiler, connection)
|
|
||||||
|
|
||||||
def get_source_expressions(self):
|
def get_source_expressions(self):
|
||||||
return self.source_expressions + self.ordering
|
return self.source_expressions + self.ordering
|
||||||
|
|
|
@ -17,3 +17,8 @@ Bugfixes
|
||||||
|
|
||||||
* Fixed a regression in Django 2.2 that caused a crash when loading the
|
* Fixed a regression in Django 2.2 that caused a crash when loading the
|
||||||
template for the technical 500 debug page (:ticket:`30324`).
|
template for the technical 500 debug page (:ticket:`30324`).
|
||||||
|
|
||||||
|
* Fixed crash of ``ordering`` argument in
|
||||||
|
:class:`~django.contrib.postgres.aggregates.ArrayAgg` and
|
||||||
|
:class:`~django.contrib.postgres.aggregates.StringAgg` when it contains an
|
||||||
|
expression with params (:ticket:`30332`).
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from django.db.models.expressions import F, Value
|
from django.db.models.expressions import F, Value
|
||||||
|
from django.db.models.functions import Concat, Substr
|
||||||
from django.test.testcases import skipUnlessDBFeature
|
from django.test.testcases import skipUnlessDBFeature
|
||||||
from django.test.utils import Approximate
|
from django.test.utils import Approximate
|
||||||
|
|
||||||
|
@ -38,6 +39,12 @@ class TestGeneralAggregate(PostgreSQLTestCase):
|
||||||
((F('boolean_field'), F('char_field').desc()), ['Foo4', 'Foo2', 'Foo3', 'Foo1']),
|
((F('boolean_field'), F('char_field').desc()), ['Foo4', 'Foo2', 'Foo3', 'Foo1']),
|
||||||
('char_field', ['Foo1', 'Foo2', 'Foo3', 'Foo4']),
|
('char_field', ['Foo1', 'Foo2', 'Foo3', 'Foo4']),
|
||||||
('-char_field', ['Foo4', 'Foo3', 'Foo2', 'Foo1']),
|
('-char_field', ['Foo4', 'Foo3', 'Foo2', 'Foo1']),
|
||||||
|
(Concat('char_field', Value('@')), ['Foo1', 'Foo2', 'Foo3', 'Foo4']),
|
||||||
|
(Concat('char_field', Value('@')).desc(), ['Foo4', 'Foo3', 'Foo2', 'Foo1']),
|
||||||
|
(
|
||||||
|
(Substr('char_field', 1, 1), F('integer_field'), Substr('char_field', 4, 1).desc()),
|
||||||
|
['Foo3', 'Foo1', 'Foo2', 'Foo4'],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
for ordering, expected_output in ordering_test_cases:
|
for ordering, expected_output in ordering_test_cases:
|
||||||
with self.subTest(ordering=ordering, expected_output=expected_output):
|
with self.subTest(ordering=ordering, expected_output=expected_output):
|
||||||
|
@ -165,6 +172,8 @@ class TestGeneralAggregate(PostgreSQLTestCase):
|
||||||
(F('char_field').desc(), 'Foo4;Foo3;Foo2;Foo1'),
|
(F('char_field').desc(), 'Foo4;Foo3;Foo2;Foo1'),
|
||||||
(F('char_field').asc(), 'Foo1;Foo2;Foo3;Foo4'),
|
(F('char_field').asc(), 'Foo1;Foo2;Foo3;Foo4'),
|
||||||
(F('char_field'), 'Foo1;Foo2;Foo3;Foo4'),
|
(F('char_field'), 'Foo1;Foo2;Foo3;Foo4'),
|
||||||
|
(Concat('char_field', Value('@')), 'Foo1;Foo2;Foo3;Foo4'),
|
||||||
|
(Concat('char_field', Value('@')).desc(), 'Foo4;Foo3;Foo2;Foo1'),
|
||||||
)
|
)
|
||||||
for ordering, expected_output in ordering_test_cases:
|
for ordering, expected_output in ordering_test_cases:
|
||||||
with self.subTest(ordering=ordering, expected_output=expected_output):
|
with self.subTest(ordering=ordering, expected_output=expected_output):
|
||||||
|
|
Loading…
Reference in New Issue