#34564: returning None instead of zero in Count annotation
-------------------------------------+-------------------------------------
               Reporter:  Amin       |          Owner:  nobody
  Aminian                            |
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  4.2
  layer (models, ORM)                |       Keywords:  count, orm,
               Severity:  Normal     |  annotate
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 I am trying to upgrade the Django's version from 3.2 to 4.2 in my project.
 after installation, some of my tests were broken.
 The problem:
 I am annotating a queryset with Count function, and the count result in
 some objects should be zero.
 This is my code:
 {{{
 Order.objects.annotate(count=Count("customer", distinct=True))
 }}}

 In Django==3.2, if some orders don't have any customers, the count field
 would be zero (as I want).
 But in Django==4.2, if some orders don't have any customers, the count
 field would be None, which breaks my code.
 I read the source code for both versions. In version 3.2, we have a method
 called `convert_value` in `Count` class in `aggregates` module. The method
 is:

 {{{
 class Count(Aggregate):
     ...
     def convert_value(self, value, expression, connection):
             return 0 if value is None else value
 }}}
 As we can see, this function is responsible to return 0 instead of None.
 But this method is deleted in version 4.2, and the conversion is handling
 in `convert_value` property in `BaseExpression` class in `expressions`
 module:

 {{{
 class BaseExpression:
     ...
     @cached_property
     def convert_value(self):
         field = self.output_field
         internal_type = field.get_internal_type()
         if internal_type == "FloatField":
             return (
                 lambda value, expression, connection: None
                 if value is None
                 else float(value)
             )
         elif internal_type.endswith("IntegerField"):
             return (
                 lambda value, expression, connection: None
                 if value is None
                 else int(value)
             )
         elif internal_type == "DecimalField":
             return (
                 lambda value, expression, connection: None
                 if value is None
                 else Decimal(value)
             )
         return self._convert_value_noop
 }}}
 In this property we are return a lambda function to be called later, and
 when we call this lambda, what ever we pass to it, we would get None as
 the result.
 Should it be something like returning 0, if the value is None ?

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34564>
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/010701881505ae69-5ae62e9d-1732-4e04-8339-abb96808d524-000000%40eu-central-1.amazonses.com.

Reply via email to