Fixed #30665 -- Added support for distinct argument to Avg() and Sum().

This commit is contained in:
Étienne Beaulé 2019-07-30 20:08:55 +02:00 committed by Mariusz Felisiak
parent cb3c2da128
commit 5f24e7158e
4 changed files with 39 additions and 4 deletions

View File

@ -99,6 +99,7 @@ class Aggregate(Func):
class Avg(FixDurationInputMixin, NumericOutputFieldMixin, Aggregate): class Avg(FixDurationInputMixin, NumericOutputFieldMixin, Aggregate):
function = 'AVG' function = 'AVG'
name = 'Avg' name = 'Avg'
allow_distinct = True
class Count(Aggregate): class Count(Aggregate):
@ -142,6 +143,7 @@ class StdDev(NumericOutputFieldMixin, Aggregate):
class Sum(FixDurationInputMixin, Aggregate): class Sum(FixDurationInputMixin, Aggregate):
function = 'SUM' function = 'SUM'
name = 'Sum' name = 'Sum'
allow_distinct = True
class Variance(NumericOutputFieldMixin, Aggregate): class Variance(NumericOutputFieldMixin, Aggregate):

View File

@ -3378,7 +3378,7 @@ by the aggregate.
``Avg`` ``Avg``
~~~~~~~ ~~~~~~~
.. class:: Avg(expression, output_field=None, filter=None, **extra) .. class:: Avg(expression, output_field=None, distinct=False, filter=None, **extra)
Returns the mean value of the given expression, which must be numeric Returns the mean value of the given expression, which must be numeric
unless you specify a different ``output_field``. unless you specify a different ``output_field``.
@ -3387,6 +3387,18 @@ by the aggregate.
* Return type: ``float`` if input is ``int``, otherwise same as input * Return type: ``float`` if input is ``int``, otherwise same as input
field, or ``output_field`` if supplied field, or ``output_field`` if supplied
Has one optional argument:
.. attribute:: distinct
If ``distinct=True``, ``Avg`` returns the mean value of unique values.
This is the SQL equivalent of ``AVG(DISTINCT <field>)``. The default
value is ``False``.
.. versionchanged:: 3.0
Support for ``distinct=True`` was added.
``Count`` ``Count``
~~~~~~~~~ ~~~~~~~~~
@ -3451,13 +3463,25 @@ by the aggregate.
``Sum`` ``Sum``
~~~~~~~ ~~~~~~~
.. class:: Sum(expression, output_field=None, filter=None, **extra) .. class:: Sum(expression, output_field=None, distinct=False, filter=None, **extra)
Computes the sum of all values of the given expression. Computes the sum of all values of the given expression.
* Default alias: ``<field>__sum`` * Default alias: ``<field>__sum``
* Return type: same as input field, or ``output_field`` if supplied * Return type: same as input field, or ``output_field`` if supplied
Has one optional argument:
.. attribute:: distinct
If ``distinct=True``, ``Sum`` returns the sum of unique values. This is
the SQL equivalent of ``SUM(DISTINCT <field>)``. The default value is
``False``.
.. versionchanged:: 3.0
Support for ``distinct=True`` was added.
``Variance`` ``Variance``
~~~~~~~~~~~~ ~~~~~~~~~~~~

View File

@ -291,6 +291,9 @@ Models
customize the get and set behavior by overriding their customize the get and set behavior by overriding their
:py:ref:`descriptors <descriptors>`. :py:ref:`descriptors <descriptors>`.
* :class:`~django.db.models.Avg` and :class:`~django.db.models.Sum` now support
the ``distinct`` argument.
Requests and Responses Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~

View File

@ -401,8 +401,14 @@ class AggregateTestCase(TestCase):
self.assertEqual(aggs['distinct_ratings'], 4) self.assertEqual(aggs['distinct_ratings'], 4)
def test_distinct_on_aggregate(self): def test_distinct_on_aggregate(self):
books = Book.objects.aggregate(ratings=Count('rating', distinct=True)) for aggregate, expected_result in (
self.assertEqual(books['ratings'], 4) (Avg, 4.125),
(Count, 4),
(Sum, 16.5),
):
with self.subTest(aggregate=aggregate.__name__):
books = Book.objects.aggregate(ratings=aggregate('rating', distinct=True))
self.assertEqual(books['ratings'], expected_result)
def test_non_grouped_annotation_not_in_group_by(self): def test_non_grouped_annotation_not_in_group_by(self):
""" """