#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 django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
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