Opened 6 years ago
Closed 5 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 , 6 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 , 6 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 , 6 years ago
| Cc: | added |
|---|
comment:4 by , 6 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 , 5 years ago
| Has patch: | set |
|---|---|
| Patch needs improvement: | set |
comment:10 by , 5 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 , 5 years ago
| Needs documentation: | set |
|---|---|
| Patch needs improvement: | set |
comment:12 by , 5 years ago
| Patch needs improvement: | unset |
|---|
comment:13 by , 5 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 BYso 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.