#34808: Some aggregation functions may return None; this isn't well documented
------------------------------------------------+------------------------
               Reporter:  Eric Baumgartner      |          Owner:  nobody
                   Type:  Cleanup/optimization  |         Status:  new
              Component:  Documentation         |        Version:  4.2
               Severity:  Normal                |       Keywords:
           Triage Stage:  Unreviewed            |      Has patch:  0
    Needs documentation:  0                     |    Needs tests:  0
Patch needs improvement:  0                     |  Easy pickings:  0
                  UI/UX:  0                     |
------------------------------------------------+------------------------
 Calls like Book.objects.filter(...).aggregate(Sum("pages")) may return
 None if the queryset is empty.

 This isn't well documented and I think many of the examples in the
 documentation can lead to folks writing unsafe code that works most of the
 time, but can fail for empty queries.

 For example (using models from
 https://docs.djangoproject.com/en/4.2/topics/db/aggregation/):

 {{{#!python
 obscure_publisher = ...
 q =
 Book.objects.filter(publisher=obscure_publisher).Aggregate(Sum("pages"))
 total_pages = q["pages"]  # None if the publisher hasn't published any
 books!

 # Silly example, but will raise a TypeError
 kilopages = total_pages / 1000
 }}}

 From what I've seen online, I think the safer approach is to use Coalesce.

 {{{#!python
 obscure_publisher = ...
 q =
 
Book.objects.filter(publisher=obscure_publisher).Aggregate(Coalesce(Sum("pages"),
 0)
 total_pages = q["pages"]  # Safe; using coalesce guarantees an int.
 }}}

 The only reference I've found to using Coalesce in this way appears to be
 a usage example at https://docs.djangoproject.com/en/4.2/ref/models
 /database-functions/#coalesce. Coalesce is not mentioned at all on the
 main aggregation page.

 I think the documentation could be improved in a few ways.

 On https://docs.djangoproject.com/en/4.2/topics/db/aggregation/:

 - The code examples could consider adding Coalesce, or at least adding a
 comment at the top of the cheat sheet section mentioning that the examples
 do not include error checking and that using Coalesce is best practice.

 For aggregation functions mentioned in
 https://docs.djangoproject.com/en/4.2/ref/models/querysets/:

 - Add something to the documentation of the return type for functions used
 by aggregate() that mentions the empty queryset case if the result type
 differs for empty queries.
 - For example, Count() safely returns an int even with empty querysets,
 but Sum, Avg, Min, and Max do not.
 - Might also be worth mentioning that one can use Coalesce to avoid having
 to deal with None values.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34808>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018a4e32cbcc-acf7f296-2855-4845-a4fb-6b3d952f13ad-000000%40eu-central-1.amazonses.com.

Reply via email to