#14357 closed Bug (fixed)
Prevent inappropriate order-based grouping on values+annotate queries
Reported by: | Martin Chase | Owned by: | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | |
Severity: | Normal | Keywords: | 3.1 |
Cc: | Simon Charette, Mariusz Felisiak | Triage Stage: | Someday/Maybe |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
class Foo(models.Model): name = models.TextField() type = models.TextField() class Meta: ordering = ["name",] Foo.objects.all().values("type").annotate(models.Count("name"))
The above code fails to generate the expected result without adding .order_by()
to the query set.
Ticket #10574 called this fixed with documentation, but indicated a proper fix would be preferred once backwards compatibility wasn't an issue. Lest this fall off the radar for being closed, I am putting this ticket in for 2.0.
Attachments (1)
Change History (27)
comment:1 by , 14 years ago
comment:2 by , 14 years ago
(that was a set & operator. sorry for the confusing notation.)
possible fallback orderings:
- pk
- only those fields which are in both the ordering and the values
- all fields in the ordering which are not also in an annotate
by , 14 years ago
Attachment: | unordering.patch added |
---|
comment:4 by , 14 years ago
Has patch: | set |
---|---|
milestone: | 2.0 |
Patch needs improvement: | set |
Triage Stage: | Unreviewed → Accepted |
comment:5 by , 14 years ago
Severity: | → Normal |
---|---|
Type: | → Bug |
comment:8 by , 12 years ago
Component: | ORM aggregation → Database layer (models, ORM) |
---|
comment:9 by , 8 years ago
Cc: | added |
---|
Simon, do you have any opinions about this change given we abandoned the idea of "Django 2.0" with large backwards incompatible changes? Not sure if a deprecation path to change the behavior is feasible.
comment:10 by , 8 years ago
I think we could and should make this change as it really common pitfall but it should follow a deprecation path.
I've personally stopped using ordering
because of its unexpected interaction with distinct()
and values()
for grouping by.
The deprecation path should detect when values()
is used for grouping on a queryset where the only defined ordering is from _meta.ordering
in the SQL compiling step and raise a deprecation warning saying such ordering will be ignored in future version of Django.
comment:11 by , 8 years ago
I think we should go as far as requiring all ordering clauses to be explicitly specified through values()
when used to group by.
For example, in the following case
Foo.objects.order_by('name').values('type').annotate(Count('name'))
A deprecation warning would be raised to notify the user that 'name'
won't automatically be added to values()
in future Django version where the previous queryset would be equivalent to the following:
Foo.objects.values('type').annotate(Count('name'))
and the current behaviour could be preserved by adding 'name'
to values()
:
Foo.objects.order_by('name').values('type', 'name').annotate(Count('name'))
I haven't tested it myself to see if it's already the case but we should also disallow ordering by a non-grouped column or aggregate alias.
Foo.objects.values('type').annotate(Count('name')).order_by('name')
should raise a value error on the order_by('name')
call.
comment:12 by , 7 years ago
I totally agree with Simon. In my opinion we shouldn't automatically add model.Meta.ordering
to values()
, values_list()
and distinct()
. I remember that a few years I lost a lot of time when I tried to figure out why the result wasn't what I expected.
comment:13 by , 7 years ago
Cc: | added |
---|
comment:16 by , 6 years ago
Summary: | Prevent innapropriate order-based grouping on values+annotate queries → Prevent inappropriate order-based grouping on values+annotate queries |
---|
comment:19 by , 6 years ago
Has patch: | unset |
---|
I'm unchecking Has patch, since the PR (deprecating ordering
being used for grouped queries was merged). What remains to close this ticket?
comment:20 by , 6 years ago
Keywords: | 3.1 added |
---|---|
Triage Stage: | Accepted → Someday/Maybe |
The behavior change will happen in Django 3.1 when the deprecation ends.
comment:22 by , 4 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
comment:23 by , 4 years ago
Resolution: | fixed |
---|---|
Status: | closed → new |
I beleave this was not properly fixed in commit 0ddb4ebf.
While commit 0ddb4ebf removes ORDER BY
when Meta.ordering is used it still does populates GROUP BY
with Meta.ordering fields thus leads to wrong aggregation.
Look to get_group_by() at compiler.py [1] - it populates GROUP BY
using previously obtained order_by with Meta.ordering
fields [2][3].
For what I see we must filter off Meta.ordering
fields from order_by in get_group_by() function.
[1] https://github.com/django/django/blob/3.1.7/django/db/models/sql/compiler.py#L128
[2] https://github.com/django/django/blob/3.1.7/django/db/models/sql/compiler.py#L56
[3] https://github.com/django/django/blob/3.1.7/django/db/models/sql/compiler.py#L286
comment:24 by , 4 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Please don't reopen closed tickets. You can create a new ticket if you can provide a sample project or test and prove that Meta.ordering
is still included.
comment:27 by , 3 years ago
For anyone surprised, just like me, that Meta.ordering
still breaks aggregation queries in Django 3.1 and 3.2, despite what the documentation says here and here, it seems that this was finally fixed in #32546 in Django 4.0. Possibly the documentation should be updated to reflect the actual version when the change was implemented, as there seems to be nothing about it in the release notes for 4.0. Or maybe the change should be backported to reflect the documentation.
possible fallback orderings: