Opened 5 years ago
Closed 4 years ago
#31573 closed New feature (fixed)
Support order_by().update() on MySQL/MariaDB.
Reported by: | Gerben Morsink | Owned by: | David Chorpash |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | update mysql order order_by |
Cc: | Adam Johnson | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When a UniqueConstraint is used on an IntegerField and we want to update multiple rows of that field at once, we need to make sure we select the right order before the update, since MySQL does not support a deferred update (see: https://dev.mysql.com/doc/refman/5.7/en/update.html).
I expected simply doing:
qs.order_by('-integerfield').update(integerfield=F('integerfield')+1) would work, but it seems the Django ORM strips the order_by from the query before execution, it gives a django.db.utils.IntegrityError: (1062, "Duplicate entry for key 'integerfield'").
Change History (14)
comment:1 by , 5 years ago
Keywords: | mysql order order_by added; queryset removed |
---|---|
Summary: | QuerySet.update().order_by() not working as expected on MySQL → Support update().order_by() on MySQL. |
Triage Stage: | Unreviewed → Accepted |
Type: | Bug → New feature |
Version: | 2.2 → master |
comment:2 by , 5 years ago
For anyone interested in implementing this feature you'll have to override the as_sql
and pre_sql_setup
method of django.db.models.sql.compiler.SQLUpdateCompiler
in django.db.backends.mysql.compiler.SQLUpdateCompiler
to avoid clearing the ordering and append the ORDER BY
clause to super().as_sql()[0]
.
comment:3 by , 5 years ago
Cc: | added |
---|
comment:4 by , 5 years ago
I imagine we'd also want a DB feature flag supports_update_order_by
to gate this behaviour.
comment:5 by , 5 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:6 by , 5 years ago
I would like to give a quick update.
I am able to get the following to work with MySQL on a unique constraint field:
QuerySet.order_by().update()
but I am still working on
QuerySet.update().order_by()
I'm also unsure how to add a feature flag here (I'm still new). I'm not sure if I just missed it in the documentation, but if anyone could point me in the right direction, that would be greatly appreciated!
follow-up: 8 comment:7 by , 5 years ago
I don't think it's possible to support .update().order_by()
because update()
doesn't return another queryset, but instead actually does the update and returns the number of rows. Supporting only the .order_by().update()
syntax seems fine to me.
comment:8 by , 5 years ago
Replying to Adam (Chainz) Johnson:
I don't think it's possible to support
.update().order_by()
becauseupdate()
doesn't return another queryset, but instead actually does the update and returns the number of rows. Supporting only the.order_by().update()
syntax seems fine to me.
Thanks for the info!
I added the following PR which allows for the use of .update().order_by()
.
comment:9 by , 4 years ago
Has patch: | set |
---|---|
Patch needs improvement: | set |
comment:10 by , 4 years ago
Patch needs improvement: | unset |
---|
Addressed comments in the PR. Added more test cases to handle a wider variety of use-cases.
comment:11 by , 4 years ago
Needs documentation: | set |
---|---|
Patch needs improvement: | set |
comment:12 by , 4 years ago
Patch needs improvement: | unset |
---|
comment:13 by , 4 years ago
Needs documentation: | unset |
---|---|
Summary: | Support update().order_by() on MySQL. → Support order_by().update() on MySQL/MariaDB. |
Triage Stage: | Accepted → Ready for checkin |
MySQL seems to be only supported engine to allow
UPDATE ... ORDER BY
so it doesn't seem to be standard.Since it's the documented way of dealing with the lack of deferrable unique constraint on MySQL I guess we could add support for it.