Django: How can I protect against concurrent modification of database entries

Ber picture Ber · Nov 26, 2008 · Viewed 43.4k times · Source

If there a way to protect against concurrent modifications of the same data base entry by two or more users?

It would be acceptable to show an error message to the user performing the second commit/save operation, but data should not be silently overwritten.

I think locking the entry is not an option, as a user might use the "Back" button or simply close his browser, leaving the lock for ever.

Answer

Andrei Savu picture Andrei Savu · Jan 30, 2010

This is how I do optimistic locking in Django:

updated = Entry.objects.filter(Q(id=e.id) && Q(version=e.version))\
          .update(updated_field=new_value, version=e.version+1)
if not updated:
    raise ConcurrentModificationException()

The code listed above can be implemented as a method in Custom Manager.

I am making the following assumptions:

  • filter().update() will result in a single database query because filter is lazy
  • a database query is atomic

These assumptions are enough to ensure that no one else has updated the entry before. If multiple rows are updated this way you should use transactions.

WARNING Django Doc:

Be aware that the update() method is converted directly to an SQL statement. It is a bulk operation for direct updates. It doesn't run any save() methods on your models, or emit the pre_save or post_save signals