Recently I've found that Django ORM's Model.save()
executes an SQL to update 'ALL' columns by default, even if nothing has been modified.
This really concerns me, because any changes I made has a chance to be set back to the original value by some other Model.save()
process.
For example, I have a model Order
. And there are two concurrent processes (P1, P2) working on it. First of all, P1 selects a row:
# P1
order = Order.objects.get(pk=10000)
Then, P2 selects the same row and updates the status
column: (the following statements can be wrapped in a transaction, or even a SERIALIZABLE one, but this can not solve the issue.)
# P2
order = Order.objects.get(pk=10000)
if order.status == UNPAID:
order.status = PAID # update the `status` column
order.save()
After that, P1 updates some other trivial column:
# P1
order.xxx = xxx # update some other trivial column
order.save() # This would set the `status` back to UNPAID !!!
order.status
would be set back to UNPAID
, and that is NOT what I want.
I know I can use save(update_fields=...)
, select_for_update()
, filter(...).update(...)
, SERIALIZABLE transaction, or explicit locking on P1 to prevent this issue.
But the thing is: It's ridiculous to use them on all Model.save()
statements in the whole project. Furthermore, even if I do in my project code, there's some other code doing this (Django Admin, ModelForm...).
Should I rewrite Model.save()
to update only those modified fields?
(It seems like a severe problem to me. Or have I taken something wrong?)