#30628 closed Bug (fixed)
order_by() on union() querysets results with wrong ordering when the same field type is presented multiple times.
Reported by: | Julien Enselme | Owned by: | Simon Charette |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 2.2 |
Severity: | Release blocker | Keywords: | |
Cc: | Simon Charette | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When doing a union of 2 querysets and then doing an order_by
on the resulting queryset, if we order on a field whose type is present multiple time, the ordering will be incorrect if the field we sort on is not the 1st field of the query. Explicitly settings values with .values('field1', 'field2')
on the base querysets or after the union has no effect.
For instance, with this model, with 2 DecimalField
s and one BooleanField
:
class Listing(models.Model): sale_price = models.DecimalField('Sale price', max_digits=10, decimal_places=2) yearly_rent = models.DecimalField('Yearly rent', max_digits=10, decimal_places=2) toto = models.BooleanField()
# Create 2 qs. qs1 = Listing.objects.all() qs2 = Listing.objects.all() # Create the union QS. qs3 = qs1.union(qs2) # Order on the 1st decimal field. This prints (which is correct) : # SELECT "union_listing"."id", "union_listing"."sale_price", "union_listing"."yearly_rent" FROM "union_listing" UNION SELECT "union_listing"."id", "union_listing"."sale_price", "union_listing"."yearly_rent" FROM "union_listing" ORDER BY (2) ASC print(qs3.order_by('sale_price').query) # Order on the 2nd deciamal field. This will print the same query as above which is incorrect. print(qs3.order_by('yearly_rent').query) # Not ordering on a DecimalField. This is correct again. print(qs3.order_by('toto').query)
From the debugging I did, it seems to come from this commit: If I revert def __eq__
back to what it was in Django 2.1 (https://github.com/django/django/blob/stable/2.1.x/django/db/models/expressions.py#L363) it works as normal again. The difference between the two methods that can explain this is that in Django 2.1, we have a check on the actual field instances thanks to other_args[1]
, but in 2.2, because of identity[2][1]
which is the class of the field, we can't distinguish two fields of the same type (please refer to the respective implementations to know the values of other_args
and identity
).
Sample projet to reproduce (sqlite db included) (Model, test file). Steps:
- Install Django 2.2
- Run
DJANGO_SETTINGS_MODULE=testunion.settings python test-script.py
- You will see the queries for
qs3.order_by('sale_price')
andqs3.order_by('yearly_rent')
They are exactly the same whereas they should be different (one withORDER BY (1)
and the other withORDER BY (2)
).
Change History (7)
comment:1 by , 5 years ago
Cc: | added |
---|---|
Severity: | Normal → Release blocker |
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 5 years ago
Summary: | Order by with union can result in invalid ORDER BY clause → order_by() on union() querysets results with wrong ordering when the same field type is presented multiple times. |
---|
comment:3 by , 5 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
Thanks for the report!
Regression in bc7e288ca9554ac1a0a19941302dea19df1acd21.
Reproduced at bc91f27a86090b4c688b56cd4e37f95eebe6e969.