Browse Source

Fixed #27767 -- Added distinct argument to ArrayAgg.

orf 8 years ago
parent
commit
b5393028bf

+ 1 - 0
AUTHORS

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

+ 4 - 0
django/contrib/postgres/aggregates/general.py

@@ -8,6 +8,10 @@ __all__ = [
 
 class ArrayAgg(Aggregate):
     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):
         if not value:

+ 8 - 1
docs/ref/contrib/postgres/aggregates.txt

@@ -22,10 +22,17 @@ General-purpose aggregation functions
 ``ArrayAgg``
 ------------
 
-.. class:: ArrayAgg(expression, **extra)
+.. class:: ArrayAgg(expression, distinct=False, **extra)
 
     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``
 ----------
 

+ 3 - 1
docs/releases/2.0.txt

@@ -72,7 +72,9 @@ Minor features
 :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`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ 9 - 1
tests/postgres_tests/test_aggregates.py

@@ -128,7 +128,7 @@ class TestGeneralAggregate(PostgreSQLTestCase):
         self.assertEqual(values, json.loads('{"jsonagg": []}'))
 
 
-class TestStringAggregateDistinct(PostgreSQLTestCase):
+class TestAggregateDistinct(PostgreSQLTestCase):
     @classmethod
     def setUpTestData(cls):
         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('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):
     @classmethod