[2.2.x] Fixed #30315 -- Fixed crash of ArrayAgg and StringAgg with ordering when used in Subquery.
Backport of a3f91891d2
from master.
This commit is contained in:
parent
5bf2c87ece
commit
1172f078eb
|
@ -33,6 +33,12 @@ class OrderableAggMixin:
|
||||||
return sql, sql_params + ordering_params
|
return sql, sql_params + ordering_params
|
||||||
return super().as_sql(compiler, connection, ordering='')
|
return super().as_sql(compiler, connection, ordering='')
|
||||||
|
|
||||||
|
def set_source_expressions(self, exprs):
|
||||||
|
# Extract the ordering expressions because ORDER BY clause is handled
|
||||||
|
# in a custom way.
|
||||||
|
self.ordering = exprs[self._get_ordering_expressions_index():]
|
||||||
|
return super().set_source_expressions(exprs[:self._get_ordering_expressions_index()])
|
||||||
|
|
||||||
def get_source_expressions(self):
|
def get_source_expressions(self):
|
||||||
return self.source_expressions + self.ordering
|
return self.source_expressions + self.ordering
|
||||||
|
|
||||||
|
|
|
@ -21,3 +21,7 @@ Bugfixes
|
||||||
|
|
||||||
* Fixed a regression in Django 2.2 where auto-reloader doesn't detect changes
|
* Fixed a regression in Django 2.2 where auto-reloader doesn't detect changes
|
||||||
in ``manage.py`` file when using ``StatReloader`` (:ticket:`30479`).
|
in ``manage.py`` file when using ``StatReloader`` (:ticket:`30479`).
|
||||||
|
|
||||||
|
* Fixed crash of :class:`~django.contrib.postgres.aggregates.ArrayAgg` and
|
||||||
|
:class:`~django.contrib.postgres.aggregates.StringAgg` with ``ordering``
|
||||||
|
argument when used in a ``Subquery`` (:ticket:`30315`).
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from django.db.models.expressions import F, Value
|
from django.db.models import CharField
|
||||||
from django.db.models.functions import Concat, Substr
|
from django.db.models.expressions import F, OuterRef, Subquery, Value
|
||||||
|
from django.db.models.functions import Cast, 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
|
||||||
|
|
||||||
|
@ -203,6 +204,36 @@ class TestGeneralAggregate(PostgreSQLTestCase):
|
||||||
values = AggregateTestModel.objects.none().aggregate(jsonagg=JSONBAgg('integer_field'))
|
values = AggregateTestModel.objects.none().aggregate(jsonagg=JSONBAgg('integer_field'))
|
||||||
self.assertEqual(values, json.loads('{"jsonagg": []}'))
|
self.assertEqual(values, json.loads('{"jsonagg": []}'))
|
||||||
|
|
||||||
|
def test_string_agg_array_agg_ordering_in_subquery(self):
|
||||||
|
stats = []
|
||||||
|
for i, agg in enumerate(AggregateTestModel.objects.order_by('char_field')):
|
||||||
|
stats.append(StatTestModel(related_field=agg, int1=i, int2=i + 1))
|
||||||
|
stats.append(StatTestModel(related_field=agg, int1=i + 1, int2=i))
|
||||||
|
StatTestModel.objects.bulk_create(stats)
|
||||||
|
|
||||||
|
for aggregate, expected_result in (
|
||||||
|
(
|
||||||
|
ArrayAgg('stattestmodel__int1', ordering='-stattestmodel__int2'),
|
||||||
|
[('Foo1', [0, 1]), ('Foo2', [1, 2]), ('Foo3', [2, 3]), ('Foo4', [3, 4])],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
StringAgg(
|
||||||
|
Cast('stattestmodel__int1', CharField()),
|
||||||
|
delimiter=';',
|
||||||
|
ordering='-stattestmodel__int2',
|
||||||
|
),
|
||||||
|
[('Foo1', '0;1'), ('Foo2', '1;2'), ('Foo3', '2;3'), ('Foo4', '3;4')],
|
||||||
|
),
|
||||||
|
):
|
||||||
|
with self.subTest(aggregate=aggregate.__class__.__name__):
|
||||||
|
subquery = AggregateTestModel.objects.filter(
|
||||||
|
pk=OuterRef('pk'),
|
||||||
|
).annotate(agg=aggregate).values('agg')
|
||||||
|
values = AggregateTestModel.objects.annotate(
|
||||||
|
agg=Subquery(subquery),
|
||||||
|
).order_by('char_field').values_list('char_field', 'agg')
|
||||||
|
self.assertEqual(list(values), expected_result)
|
||||||
|
|
||||||
|
|
||||||
class TestAggregateDistinct(PostgreSQLTestCase):
|
class TestAggregateDistinct(PostgreSQLTestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
Loading…
Reference in New Issue