From 18c8ced81e4a6e093c732f8cded3b16426d16952 Mon Sep 17 00:00:00 2001 From: Artur Beltsov Date: Wed, 4 Nov 2020 16:30:47 +0500 Subject: [PATCH] Fixed #32169 -- Added distinct support to JSONBAgg. --- django/contrib/postgres/aggregates/general.py | 3 ++- docs/ref/contrib/postgres/aggregates.txt | 9 ++++++++- docs/releases/3.2.txt | 3 +++ tests/postgres_tests/test_aggregates.py | 12 ++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/django/contrib/postgres/aggregates/general.py b/django/contrib/postgres/aggregates/general.py index ea94ab282a..27cfe316e9 100644 --- a/django/contrib/postgres/aggregates/general.py +++ b/django/contrib/postgres/aggregates/general.py @@ -43,7 +43,8 @@ class BoolOr(Aggregate): class JSONBAgg(OrderableAggMixin, Aggregate): function = 'JSONB_AGG' - template = '%(function)s(%(expressions)s %(ordering)s)' + template = '%(function)s(%(distinct)s%(expressions)s %(ordering)s)' + allow_distinct = True output_field = JSONField() def convert_value(self, value, expression, connection): diff --git a/docs/ref/contrib/postgres/aggregates.txt b/docs/ref/contrib/postgres/aggregates.txt index 31202d5304..c309dcad14 100644 --- a/docs/ref/contrib/postgres/aggregates.txt +++ b/docs/ref/contrib/postgres/aggregates.txt @@ -114,10 +114,17 @@ General-purpose aggregation functions ``JSONBAgg`` ------------ -.. class:: JSONBAgg(expressions, filter=None, ordering=(), **extra) +.. class:: JSONBAgg(expressions, distinct=False, filter=None, ordering=(), **extra) Returns the input values as a ``JSON`` array. + .. attribute:: distinct + + .. versionadded:: 3.2 + + An optional boolean argument that determines if array values will be + distinct. Defaults to ``False``. + .. attribute:: ordering .. versionadded:: 3.2 diff --git a/docs/releases/3.2.txt b/docs/releases/3.2.txt index ca427c3bc5..e76223f6d4 100644 --- a/docs/releases/3.2.txt +++ b/docs/releases/3.2.txt @@ -131,6 +131,9 @@ Minor features * The new :attr:`.JSONBAgg.ordering` attribute determines the ordering of the aggregated elements. +* The new :attr:`.JSONBAgg.distinct` attribute determines if aggregated values + will be distinct. + * The :class:`~django.contrib.postgres.operations.CreateExtension` operation now checks that the extension already exists in the database and skips the migration if so. diff --git a/tests/postgres_tests/test_aggregates.py b/tests/postgres_tests/test_aggregates.py index 06cca6313d..064536a2c6 100644 --- a/tests/postgres_tests/test_aggregates.py +++ b/tests/postgres_tests/test_aggregates.py @@ -428,6 +428,18 @@ class TestAggregateDistinct(PostgreSQLTestCase): values = AggregateTestModel.objects.aggregate(arrayagg=ArrayAgg('char_field', distinct=True)) self.assertEqual(sorted(values['arrayagg']), ['Bar', 'Foo']) + def test_json_agg_distinct_false(self): + values = AggregateTestModel.objects.aggregate( + jsonagg=JSONBAgg('char_field', distinct=False), + ) + self.assertEqual(sorted(values['jsonagg']), ['Bar', 'Foo', 'Foo']) + + def test_json_agg_distinct_true(self): + values = AggregateTestModel.objects.aggregate( + jsonagg=JSONBAgg('char_field', distinct=True), + ) + self.assertEqual(sorted(values['jsonagg']), ['Bar', 'Foo']) + class TestStatisticsAggregate(PostgreSQLTestCase): @classmethod