summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authororf <tom@tomforb.es>2017-01-23 15:34:42 +0000
committerTim Graham <timograham@gmail.com>2017-02-04 13:57:39 -0500
commitb5393028bfc939adf14d0fa5e4088cddd3b9dfa1 (patch)
tree4168b42b77be5bce7d3b8d0acf2819098344412c
parent245f20910906c8f17e1011a00f7042e1d8f39c76 (diff)
Fixed #27767 -- Added distinct argument to ArrayAgg.
-rw-r--r--AUTHORS1
-rw-r--r--django/contrib/postgres/aggregates/general.py4
-rw-r--r--docs/ref/contrib/postgres/aggregates.txt9
-rw-r--r--docs/releases/2.0.txt4
-rw-r--r--tests/postgres_tests/test_aggregates.py10
5 files changed, 25 insertions, 3 deletions
diff --git a/AUTHORS b/AUTHORS
index 99c71549aa..984b49f4f5 100644
--- a/AUTHORS
+++ b/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>
diff --git a/django/contrib/postgres/aggregates/general.py b/django/contrib/postgres/aggregates/general.py
index ac18a516d6..91835a9ca3 100644
--- a/django/contrib/postgres/aggregates/general.py
+++ b/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:
diff --git a/docs/ref/contrib/postgres/aggregates.txt b/docs/ref/contrib/postgres/aggregates.txt
index 3939023e26..1c738c35ae 100644
--- a/docs/ref/contrib/postgres/aggregates.txt
+++ b/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``
----------
diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt
index 4e42bd2b55..a43ae5e368 100644
--- a/docs/releases/2.0.txt
+++ b/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`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/postgres_tests/test_aggregates.py b/tests/postgres_tests/test_aggregates.py
index 9aa0e06595..056d08441b 100644
--- a/tests/postgres_tests/test_aggregates.py
+++ b/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