Opened 10 years ago
Last modified 10 years ago
#24692 closed Cleanup/optimization
QuerySet.extra(select=...) is silently dropped with aggregations — at Version 3
Reported by: | jdelic | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.8 |
Severity: | Normal | Keywords: | |
Cc: | mbertheau@… | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Here is a minimal example:
from django.db import models class Service(models.Model): name = models.TextField() class ServiceAction(models.Model): performed = models.DateTimeField(auto_now_add=True) service = models.ForeignKey(Service)
Then add some models:
>>> from dbtest.models import Service, ServiceAction >>> from django.db.models import Min, Max >>> s1 = Service.objects.create(name='test1') >>> s2 = Service.objects.create(name='test2') >>> ServiceAction.objects.create(service_id=s1.id) >>> ServiceAction.objects.create(service_id=s1.id) >>> ServiceAction.objects.create(service_id=s1.id) >>> ServiceAction.objects.create(service_id=s2.id) >>> ServiceAction.objects.create(service_id=s2.id) >>> ServiceAction.objects.create(service_id=s2.id)
...and query them using aggregations:
>>> qs = ServiceAction.objects.extra(select={'period': '(MAX("dbtest_serviceaction"."performed")-MIN("dbtest_serviceaction"."performed"))'}).values('service_id').annotate(first_action=Min('performed'), last_action=Max('performed')) >>> print(qs.query) SELECT "dbtest_serviceaction"."service_id", MAX("dbtest_serviceaction"."performed") AS "last_action", MIN("dbtest_serviceaction"."performed") AS "first_action" FROM "dbtest_serviceaction" GROUP BY "dbtest_serviceaction"."service_id"
As you can see the .extra(select=...)
has been dropped from the query. I assume this happens on Django 1.6.x, 1.7.x and 1.8.x, but I have only tested 1.6.11 and 1.8.
The expected outcome would have been:
SELECT "dbtest_serviceaction"."service_id", MAX("dbtest_serviceaction"."performed") AS "last_action", MIN("dbtest_serviceaction"."performed") AS "first_action", MAX("dbtest_serviceaction"."performed")-MIN("dbtest_serviceaction"."performed") as "period" FROM "dbtest_serviceaction" GROUP BY "dbtest_serviceaction"."service_id"
Using Django 1.8 this exact query can be performed with the ORM itself through the use of the newly added operators for aggregations:
>>> qs = ServiceAction.objects.values('service_id').annotate(first_action=Min('performed'), last_action=Max('performed'), period=Max('performed')-Min('performed')) >>> print(qs.query) SELECT "dbtest_serviceaction"."service_id", (MAX("dbtest_serviceaction"."performed") - MIN("dbtest_serviceaction"."performed")) AS "period", MAX("dbtest_serviceaction"."performed") AS "last_action", MIN("dbtest_serviceaction"."performed") AS "first_action" FROM "dbtest_serviceaction" GROUP BY "dbtest_serviceaction"."service_id"
Change History (3)
comment:1 by , 10 years ago
Description: | modified (diff) |
---|
comment:2 by , 10 years ago
Cc: | added |
---|
comment:3 by , 10 years ago
Description: | modified (diff) |
---|
Note:
See TracTickets
for help on using tickets.