@@ -60,14 +60,16 @@ above:
6060 >>> Book.objects.filter(publisher__name="BaloneyPress").count()
6161 73
6262
63- # Average price across all books.
63+ # Average price across all books, provide default to be returned instead
64+ # of None if no books exist.
6465 >>> from django.db.models import Avg
65- >>> Book.objects.aggregate(Avg("price"))
66+ >>> Book.objects.aggregate(Avg("price", default=0 ))
6667 {'price__avg': 34.35}
6768
68- # Max price across all books.
69+ # Max price across all books, provide default to be returned instead of
70+ # None if no books exist.
6971 >>> from django.db.models import Max
70- >>> Book.objects.aggregate(Max("price"))
72+ >>> Book.objects.aggregate(Max("price", default=0 ))
7173 {'price__max': Decimal('81.20')}
7274
7375 # 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:
632634 >>> from django.db.models import Avg, Count
633635 >>> Book.objects.annotate(num_authors=Count("authors")).aggregate(Avg("num_authors"))
634636 {'num_authors__avg': 1.66}
637+
638+ Aggregating on empty querysets or groups
639+ ----------------------------------------
640+
641+ When an aggregation is applied to an empty queryset or grouping, the result
642+ defaults to its :ref:`default <aggregate-default>` parameter, typically
643+ ``None``. This behavior occurs because aggregate functions return ``NULL`` when
644+ the executed query returns no rows.
645+
646+ You can specify a return value by providing the :ref:`default
647+ <aggregate-default>` argument for most aggregations. However, since
648+ :class:`~django.db.models.Count` does not support the :ref:`default
649+ <aggregate-default>` argument, it will always return ``0`` for empty querysets
650+ or groups.
651+
652+ For example, assuming that no book contains *web* in its name, calculating the
653+ total price for this book set would return ``None`` since there are no matching
654+ rows to compute the :class:`~django.db.models.Sum` aggregation on:
655+
656+ .. code-block:: pycon
657+
658+ >>> from django.db.models import Sum
659+ >>> Book.objects.filter(name__contains="web").aggregate(Sum("price"))
660+ {"price__sum": None}
661+
662+ However, the :ref:`default <aggregate-default>` argument can be set when
663+ calling :class:`~django.db.models.Sum` to return a different default value if
664+ no books can be found:
665+
666+ .. code-block:: pycon
667+
668+ >>> Book.objects.filter(name__contains="web").aggregate(Sum("price", default=0))
669+ {"price__sum": Decimal("0")}
670+
671+ Under the hood, the :ref:`default <aggregate-default>` argument is implemented
672+ by wrapping the aggregate function with
673+ :class:`~django.db.models.functions.Coalesce`.
0 commit comments