Django: How to acquire a lock on the database rows?
select_for_update is the answer if you want to acquire a lock on the row. The lock is only released after the transaction is completed. This is similar to the
Select for update statement in the SQL query.
>>> Dealership.objects.select_for_update().get(pk='iamid') >>> # Here lock is only required on Dealership object >>> Dealership.objects.select_related('oem').select_for_update(of=('self',))
select_for_update have these four arguments with these default value
Let's see what these all arguments mean
Think of the scenario where the lock is already acquired by another query, in this case, you want your query to wait or raise an error, This behavior can be controlled by
nowait=True we will raise the
DatabaseError otherwise it will wait for the lock to be released.
As somewhat name implies, it helps to decide whether to consider a locked row in the evaluated query. If the
skip_locked=true locked rows will not be considered.
nowait and skip_locked are mutually exclusive using both together will raise ValueError
select_for_update when the query is evaluated, the lock is also acquired on the select related rows as in the query. If one doesn't wish the same, they can use
of where they can specify fields to acquire a lock on
>>> Dealership.objects.select_related('oem').select_for_update(of=('self',)) # Just be sure we don't have any nullable relation with OEM
This helps you to create a weak lock. This means the other query can create new rows which refer to the locked rows (any reference relationship).
Few more important points to keep in mind
select_for_update doesn't allow nullable relations, you have to explicitly exclude these nullable conditions. In auto-commit mode,
select_for_update fails with error
TransactionManagementError you have to add code in a transaction explicitly. I have struggled around these points :).
Here is all about
select_for_update which you require to know to use in your code and to do changes to your database.