According to Django docs:
Usually, if another transaction has already acquired a lock on one of the selected rows, the query will block until the lock is released. If this is not the behavior you want, call select_for_update(nowait=True). This will make the call non-blocking. If a conflicting lock is already acquired by another transaction, DatabaseError will be raised when the queryset is evaluated.
I was experimenting with this but found a strange behavior. Below code when run simultaneously doesn't raise the error but works in a blocking manner.
def test4():
with transaction.atomic():
WorkflowCallContact.objects.select_for_update(nowait=True).filter(id__in=[1,2,3,4]).update(number="22222")
time.sleep(10)
list(WorkflowCallContact.objects.filter(id__in=[1,2,3,4]))
To test, I am just opening to shells and calling the same function parallelly. But instead of throwing DatabaseError on the second call because of nowait=True, the call becomes blocked for 10 secs.
Database I'm using: postgres Django version: 1.9
select_for_update() and update() can't be chained. You have to force the QuerySet to be evaluated, for example by converting it to a list():
with transaction.atomic():
list(WorkflowCallContact.objects.select_for_update(nowait=True).filter(id__in=[1,2,3,4]))
WorkflowCallContact.objects.filter(id__in=[1,2,3,4]).update(number="22222")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With