#28811 closed Bug (fixed)
KeyError when using a regular annotation inside an F-statement in a group by annotation
Reported by: | Robin Ramael | Owned by: | Robin Ramael |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.11 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description
When a queryset is first annotated in the regular way (just adding a column), and then that annotation is used inside an F-expression in a group by-annotation, the query generation crashes with a KeyError because it can't find the first annotation.
Code to reproduce:
models.py:
from django.db import models class Data(models.Model): option = models.CharField(max_length=2) value = models.FloatField()
tests.py:
from django.db.models import F, Sum, Value from django.test import TestCase from .models import Data, Thing class AnnotateTests(TestCase): def test_simple(self): Data.objects.create(option='A', value=1) Data.objects.create(option='A', value=2) Data.objects.create(option='B', value=3) Data.objects.create(option='B', value=4) data_qs = (Data.objects .annotate(multiplier=Value(3)) # will of course be far more complex in the wild # group by option => sum of value * multiplier .values('option') .annotate(multiplied_value_sum=Sum(F('multiplier') * F('value'))) .order_by()) print(list(data_qs))
There is a workaround, though: replacing the F-expression in the second with the value of the first doesn't require the annotation lookup, avoiding the KeyError, so the solution for this might just be a better error message, although this gets unwieldy for complex annotations.
Running this test will result in the following traceback:
Creating test database for alias 'default'... System check identified no issues (0 silenced). E ====================================================================== ERROR: test_simple (annotate.tests.AnnotateTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/robin/src/ormweirdness/annotate/tests.py", line 21, in test_simple .annotate(multiplied_value_sum=Sum(F('multiplier') * F('value'))) File "/Users/robin/.virtualenvs/ormweirdness/lib/python3.6/site-packages/django/db/models/query.py", line 945, in annotate clone.query.add_annotation(annotation, alias, is_summary=False) File "/Users/robin/.virtualenvs/ormweirdness/lib/python3.6/site-packages/django/db/models/sql/query.py", line 973, in add_annotation summarize=is_summary) File "/Users/robin/.virtualenvs/ormweirdness/lib/python3.6/site-packages/django/db/models/aggregates.py", line 19, in resolve_expression c = super(Aggregate, self).resolve_expression(query, allow_joins, reuse, summarize) File "/Users/robin/.virtualenvs/ormweirdness/lib/python3.6/site-packages/django/db/models/expressions.py", line 548, in resolve_expression c.source_expressions[pos] = arg.resolve_expression(query, allow_joins, reuse, summarize, for_save) File "/Users/robin/.virtualenvs/ormweirdness/lib/python3.6/site-packages/django/db/models/expressions.py", line 411, in resolve_expression c.lhs = c.lhs.resolve_expression(query, allow_joins, reuse, summarize, for_save) File "/Users/robin/.virtualenvs/ormweirdness/lib/python3.6/site-packages/django/db/models/expressions.py", line 471, in resolve_expression return query.resolve_ref(self.name, allow_joins, reuse, summarize) File "/Users/robin/.virtualenvs/ormweirdness/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1472, in resolve_ref return self.annotation_select[name] KeyError: 'multiplier' ---------------------------------------------------------------------- Ran 1 test in 0.004s FAILED (errors=1) Destroying test database for alias 'default'...
I've found one person that also seemed to have this problem on the django-users mailing list: https://groups.google.com/forum/#!topic/django-users/SYAGaVuEjHY
Happens on Django 1.11.7, python3.6. sqlite3 as well as postgres10.
Attachments (1)
Change History (9)
comment:1 by , 7 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 7 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
by , 7 years ago
Attachment: | patchfor28811.diff added |
---|
comment:3 by , 7 years ago
Has patch: | set |
---|
comment:4 by , 7 years ago
Patch needs improvement: | set |
---|
Are you able to send a pull request? Please reuse an existing model rather than adding a new one. Perhaps using Publisher
in tests/annotations
would be fine.
comment:5 by , 7 years ago
Opened a PR with the requested changes here: https://github.com/django/django/pull/9528/
comment:7 by , 7 years ago
This bug is also present in 1.11. Any chance it might be merged into that branch as well?
patch