Fixed #30315 -- Fixed crash of ArrayAgg and StringAgg with ordering when used in Subquery.
This commit is contained in:
parent
b2790f74d4
commit
a3f91891d2
|
@ -33,6 +33,12 @@ class OrderableAggMixin:
|
|||
return sql, sql_params + ordering_params
|
||||
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):
|
||||
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
|
||||
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
|
||||
|
||||
from django.db.models.expressions import F, Value
|
||||
from django.db.models.functions import Concat, Substr
|
||||
from django.db.models import CharField
|
||||
from django.db.models.expressions import F, OuterRef, Subquery, Value
|
||||
from django.db.models.functions import Cast, Concat, Substr
|
||||
from django.test.utils import Approximate
|
||||
|
||||
from . import PostgreSQLTestCase
|
||||
|
@ -202,6 +203,36 @@ class TestGeneralAggregate(PostgreSQLTestCase):
|
|||
values = AggregateTestModel.objects.none().aggregate(jsonagg=JSONBAgg('integer_field'))
|
||||
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):
|
||||
@classmethod
|
||||
|
|
Loading…
Reference in New Issue