Skip to content

Commit

Permalink
Fixed #34808 -- Doc'd aggregate function's default argument.
Browse files Browse the repository at this point in the history
  • Loading branch information
lufafajoshua authored and nessita committed Oct 11, 2023
1 parent fc62e17 commit 8adc7c8
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 10 deletions.
18 changes: 12 additions & 6 deletions docs/ref/models/querysets.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3909,7 +3909,8 @@ by the aggregate.

* Default alias: ``<field>__avg``
* Return type: ``float`` if input is ``int``, otherwise same as input
field, or ``output_field`` if supplied
field, or ``output_field`` if supplied. If the queryset or grouping is
empty, ``default`` is returned.

.. attribute:: distinct

Expand Down Expand Up @@ -3947,7 +3948,8 @@ by the aggregate.
Returns the maximum value of the given expression.

* Default alias: ``<field>__max``
* Return type: same as input field, or ``output_field`` if supplied
* Return type: same as input field, or ``output_field`` if supplied. If the
queryset or grouping is empty, ``default`` is returned.

``Min``
~~~~~~~
Expand All @@ -3957,7 +3959,8 @@ by the aggregate.
Returns the minimum value of the given expression.

* Default alias: ``<field>__min``
* Return type: same as input field, or ``output_field`` if supplied
* Return type: same as input field, or ``output_field`` if supplied. If the
queryset or grouping is empty, ``default`` is returned.

``StdDev``
~~~~~~~~~~
Expand All @@ -3968,7 +3971,8 @@ by the aggregate.

* Default alias: ``<field>__stddev``
* Return type: ``float`` if input is ``int``, otherwise same as input
field, or ``output_field`` if supplied
field, or ``output_field`` if supplied. If the queryset or grouping is
empty, ``default`` is returned.

.. attribute:: sample

Expand All @@ -3984,7 +3988,8 @@ by the aggregate.
Computes the sum of all values of the given expression.

* 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. If the
queryset or grouping is empty, ``default`` is returned.

.. attribute:: distinct

Expand All @@ -4001,7 +4006,8 @@ by the aggregate.

* Default alias: ``<field>__variance``
* Return type: ``float`` if input is ``int``, otherwise same as input
field, or ``output_field`` if supplied
field, or ``output_field`` if supplied. If the queryset or grouping is
empty, ``default`` is returned.

.. attribute:: sample

Expand Down
47 changes: 43 additions & 4 deletions docs/topics/db/aggregation.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,16 @@ above:
>>> Book.objects.filter(publisher__name="BaloneyPress").count()
73

# Average price across all books.
# Average price across all books, provide default to be returned instead
# of None if no books exist.
>>> from django.db.models import Avg
>>> Book.objects.aggregate(Avg("price"))
>>> Book.objects.aggregate(Avg("price", default=0))
{'price__avg': 34.35}

# Max price across all books.
# Max price across all books, provide default to be returned instead of
# None if no books exist.
>>> from django.db.models import Max
>>> Book.objects.aggregate(Max("price"))
>>> Book.objects.aggregate(Max("price", default=0))
{'price__max': Decimal('81.20')}

# Difference between the highest priced book and the average price of all books.
Expand Down Expand Up @@ -632,3 +634,40 @@ aggregate that author count, referencing the annotation field:
>>> from django.db.models import Avg, Count
>>> Book.objects.annotate(num_authors=Count("authors")).aggregate(Avg("num_authors"))
{'num_authors__avg': 1.66}

Aggregating on empty querysets or groups
----------------------------------------

When an aggregation is applied to an empty queryset or grouping, the result
defaults to its :ref:`default <aggregate-default>` parameter, typically
``None``. This behavior occurs because aggregate functions return ``NULL`` when
the executed query returns no rows.

You can specify a return value by providing the :ref:`default
<aggregate-default>` argument for most aggregations. However, since
:class:`~django.db.models.Count` does not support the :ref:`default
<aggregate-default>` argument, it will always return ``0`` for empty querysets
or groups.

For example, assuming that no book contains *web* in its name, calculating the
total price for this book set would return ``None`` since there are no matching
rows to compute the :class:`~django.db.models.Sum` aggregation on:

.. code-block:: pycon

>>> from django.db.models import Sum
>>> Book.objects.filter(name__contains="web").aggregate(Sum("price"))
{"price__sum": None}

However, the :ref:`default <aggregate-default>` argument can be set when
calling :class:`~django.db.models.Sum` to return a different default value if
no books can be found:

.. code-block:: pycon

>>> Book.objects.filter(name__contains="web").aggregate(Sum("price", default=0))
{"price__sum": Decimal("0")}

Under the hood, the :ref:`default <aggregate-default>` argument is implemented
by wrapping the aggregate function with
:class:`~django.db.models.functions.Coalesce`.

0 comments on commit 8adc7c8

Please sign in to comment.