#30542: Float-valued aggregations and annotations with filters fail with
AttributeError
-------------------------------------+-------------------------------------
               Reporter:  Chuan-     |          Owner:  nobody
  Zheng Lee                          |
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  2.2
  layer (models, ORM)                |       Keywords:  aggregation,
               Severity:  Normal     |  annotation, filter
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 When any float-valued aggregation or annotation (`Avg`, `StdDev`,
 `Variance`) is used with the `filter=` keyword argument, the following
 exception is raised:
 {{{
 AttributeError: 'WhereNode' object has no attribute 'output_field'
 }}}

 For example, these queries all fail with this error:
 {{{#!python
 Speaker.objects.annotate(average=Avg('speakerscore__score',
 filter=Q(speakerscore__ghost=False)))
 Speaker.objects.annotate(average=StdDev('speakerscore__score',
 filter=Q(speakerscore__ghost=False)))
 Team.objects.annotate(average=Avg('debateteam__teamscore__score',
 filter=Q(debateteam__teamscore__forfeit=False)))
 }}}

 The error seems to be raised irrespective of what's in the database
 (''e.g.'', it's raised even for an empty database). However, it doesn't
 affect aggregations like `Sum`, `Max` or `Min` that don't use
 `NumericOutputFieldMixin`. Also, queries that don't use the `filter=`
 keyword in the aggregation work fine.

 The exception in question is raised from line 46 of
 django/db/models/functions/mixins.py, which looks for an `output_field`
 attribute of every element of `self.get_source_expressions()`, where
 `self` is the object containing `NumericOutputFieldMixin`, in this case
 `Avg` or some other subclass of `Aggregate`. But
 `Aggregate.get_source_expressions()` includes `self.filter` in its list,
 and (post-compilation) `self.filter` is a `WhereNode`, which doesn't have
 an `output_field` attribute.

 This issue is new in version 2.2. Everything works fine in version 2.1
 (where I believe `NumericOutputFieldMixin` didn't exist, or at least
 wasn't on the MRO for `Avg`, `StdDev` or `Variance`).

 === Minimal reproducible example

 In a blank (or any) project, insert in models.py:
 {{{#!python
 from django.db.models import Model, FloatField, BooleanField

 class Book(Model):
     price = FloatField()
     fiction = BooleanField()
 }}}
 then run migrations and in `python manage.py shell`:
 {{{
 $ python manage.py shell
 Python 3.6.7 (default, Oct 22 2018, 11:32:17)
 [GCC 8.2.0] on linux
 Type "help", "copyright", "credits" or "license" for more information.
 (InteractiveConsole)
 >>> from django22_output_field_bug.models import Book
 >>> from django.db.models import Avg, Q
 >>> Book.objects.annotate(average=Avg('price', filter=Q(fiction=True)))
 Traceback (most recent call last):
 [...]
   File "/[...]/django/db/models/functions/mixins.py", line 46, in
 <genexpr>
     if any(isinstance(s.output_field, DecimalField) for s in
 source_expressions):
 AttributeError: 'WhereNode' object has no attribute 'output_field'
 >>> Book.objects.aggregate(average=Avg('price', filter=Q(fiction=True)))
 Traceback (most recent call last):
 [...]
   File "/[...]/django/db/models/functions/mixins.py", line 46, in
 <genexpr>
     if any(isinstance(s.output_field, DecimalField) for s in
 source_expressions):
 AttributeError: 'WhereNode' object has no attribute 'output_field'
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/30542>
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 post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/048.1d8992093063682dc93e81858a194906%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to