summaryrefslogtreecommitdiff
path: root/docs/topics
diff options
context:
space:
mode:
authorlufafajoshua <lufafajosh@gmail.com>2023-09-25 13:25:33 +0300
committerNatalia <124304+nessita@users.noreply.github.com>2023-10-11 16:11:09 -0300
commite8fe48d3a02dbe3b57a87b334f6335b701f0306d (patch)
tree8c2ebf2cbc0be14ec846708d15dafd2ea30a5fdc /docs/topics
parent830990fa6ca4a76489ce6c943fce3fd0123a449f (diff)
[4.2.x] Fixed #34808 -- Doc'd aggregate function's default argument.
Backport of 8adc7c86ab85ed91e512bc49056e301cbe1715d0 from main
Diffstat (limited to 'docs/topics')
-rw-r--r--docs/topics/db/aggregation.txt47
1 files changed, 43 insertions, 4 deletions
diff --git a/docs/topics/db/aggregation.txt b/docs/topics/db/aggregation.txt
index 3cb674aa95..9f98504c0c 100644
--- a/docs/topics/db/aggregation.txt
+++ b/docs/topics/db/aggregation.txt
@@ -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.
@@ -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`.