#34564: returning None instead of zero in Count annotation
-------------------------------------+-------------------------------------
     Reporter:  Amin Aminian         |                    Owner:  Amin
                                     |  Aminian
         Type:  Bug                  |                   Status:  assigned
    Component:  Database layer       |                  Version:  4.2
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:  count, orm,          |             Triage Stage:  Accepted
  annotate                           |
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Simon Charette):

 Thanks for your consideration Mariusz, I missed that it wasn't a recent
 regression, time fly by!

 If that can help you Amin, the ORM compiler has some logic in place to
 prevent doing database queries when it knows that it cannot match any rows
 (e.g. `id__in=[]`). When this happens (aggregation or when annotating
 subqueries that don't match any rows) we still need to provide some values
 to the user that are coherent with what would have happened if the query
 was still performed, that's when `empty_result_set_value` kicks in. You
 might notice in this patch that `QuerySet.none()` is used, that's a public
 way of making sure that evaluating the queryset results in no query.

 Through a series a patch that tried to make the logic more coherent in
 this area and the introduction of `Aggregate(..., default=default)` which
 is basically a shorthand for `Coalesce(Aggregate(...), default)` the
 `empty().aggregate(cnt=Count())` long standing issue where `{"cnt": None}`
 was returned was fixed (due to `Count.empty_result_set_value = 0`) but
 surprisingly (this is mind blowing to me) we didn't have any tests for the
 case where `.annotate(cnt=Cnt("possibly_empty_multi_value"))` so
 `convert_value` was wrongly removed assuming that it was covered by the
 adjusted logic.

 As for the patch I'm pretty sure I could see us going to ways
 1. Drop `Count.empty_result_set_value` to use `extra["default"] = 0` so
 `Coalesce(..., 0)` is systematically used and we inherit the
 `empty_result_set_value` from the `Coaesce` and `Value` chain. This might
 require adjusting some tests that check the exact SQL generated or assert
 that `Count(default)` cannot be used.
 2. Simply add back the `convert_value` that were removed in
 9f3cce172f6913c5ac74272fa5fc07f847b4e112

 1. seems more desirable to me as it pushes the logic to the database and
 avoids Python time conversions (`convert_value` comes at a cost as its run
 for each row) while 2. is less invasive as it requires no test changes and
 keeps the generated SQL the same (no `Coalesce` wrapping for each usage of
 `Count`).

 Whatever solution we choose we should make sure to add address the same
 issue we have with `RegrCount`.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34564#comment:8>
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/010701881a6fd526-de444877-e078-4fa1-91dc-cba46479606d-000000%40eu-central-1.amazonses.com.

Reply via email to