Fixed #27767 -- Added distinct argument to ArrayAgg.

This commit is contained in:
orf 2017-01-23 15:34:42 +00:00 committed by Tim Graham
parent 245f209109
commit b5393028bf
5 changed files with 25 additions and 3 deletions

View File

@ -756,6 +756,7 @@ answer newbie questions, and generally made Django that much better:
tobias@neuyork.de tobias@neuyork.de
Todd O'Bryan <toddobryan@mac.com> Todd O'Bryan <toddobryan@mac.com>
Tom Christie <tom@tomchristie.com> Tom Christie <tom@tomchristie.com>
Tom Forbes <tom@tomforb.es>
Tom Insam Tom Insam
Tom Tobin Tom Tobin
Tomáš Ehrlich <tomas.ehrlich@gmail.com> Tomáš Ehrlich <tomas.ehrlich@gmail.com>

View File

@ -8,6 +8,10 @@ __all__ = [
class ArrayAgg(Aggregate): class ArrayAgg(Aggregate):
function = 'ARRAY_AGG' function = 'ARRAY_AGG'
template = '%(function)s(%(distinct)s%(expressions)s)'
def __init__(self, expression, distinct=False, **extra):
super().__init__(expression, distinct='DISTINCT ' if distinct else '', **extra)
def convert_value(self, value, expression, connection, context): def convert_value(self, value, expression, connection, context):
if not value: if not value:

View File

@ -22,10 +22,17 @@ General-purpose aggregation functions
``ArrayAgg`` ``ArrayAgg``
------------ ------------
.. class:: ArrayAgg(expression, **extra) .. class:: ArrayAgg(expression, distinct=False, **extra)
Returns a list of values, including nulls, concatenated into an array. Returns a list of values, including nulls, concatenated into an array.
.. attribute:: distinct
.. versionadded:: 2.0
An optional boolean argument that determines if array values
will be distinct. Defaults to ``False``.
``BitAnd`` ``BitAnd``
---------- ----------

View File

@ -72,7 +72,9 @@ Minor features
:mod:`django.contrib.postgres` :mod:`django.contrib.postgres`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ... * The new ``distinct`` argument for
:class:`~django.contrib.postgres.aggregates.ArrayAgg` determines if
concatenated values will be distinct.
:mod:`django.contrib.redirects` :mod:`django.contrib.redirects`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -128,7 +128,7 @@ class TestGeneralAggregate(PostgreSQLTestCase):
self.assertEqual(values, json.loads('{"jsonagg": []}')) self.assertEqual(values, json.loads('{"jsonagg": []}'))
class TestStringAggregateDistinct(PostgreSQLTestCase): class TestAggregateDistinct(PostgreSQLTestCase):
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
AggregateTestModel.objects.create(char_field='Foo') AggregateTestModel.objects.create(char_field='Foo')
@ -145,6 +145,14 @@ class TestStringAggregateDistinct(PostgreSQLTestCase):
self.assertEqual(values['stringagg'].count('Foo'), 1) self.assertEqual(values['stringagg'].count('Foo'), 1)
self.assertEqual(values['stringagg'].count('Bar'), 1) self.assertEqual(values['stringagg'].count('Bar'), 1)
def test_array_agg_distinct_false(self):
values = AggregateTestModel.objects.aggregate(arrayagg=ArrayAgg('char_field', distinct=False))
self.assertEqual(sorted(values['arrayagg']), ['Bar', 'Foo', 'Foo'])
def test_array_agg_distinct_true(self):
values = AggregateTestModel.objects.aggregate(arrayagg=ArrayAgg('char_field', distinct=True))
self.assertEqual(sorted(values['arrayagg']), ['Bar', 'Foo'])
class TestStatisticsAggregate(PostgreSQLTestCase): class TestStatisticsAggregate(PostgreSQLTestCase):
@classmethod @classmethod