Django select_for_update(nowait=False) in transaction.atomic() does not work as expected

I have a django app that needs to get a unique ID. Many threads run at the same time that need one. I would like the IDs to be sequential. When I need a unique ID I do this:

with transaction.atomic():
    max_batch_id = JobStatus.objects.select_for_update(nowait=False).aggregate(Max('batch_id'))
    json_dict['batch_id'] = max_batch_id['batch_id__max'] + 1
    status_row = JobStatus(**json_dict)
    status_row.save()

But multiple jobs are getting the same ID. Why does the code not work as I expect? What is a better way to accomplish what I need? I cannot use the row id as there are many rows that have the same batch_id.

As Django docs says in Docs, you can use F() for avoiding race condition:

The process can be made robust, avoiding a race condition, as well as slightly faster by expressing the update relative to the original field value, rather than as an explicit assignment of a new value. Django provides F expressions for performing this kind of relative update.

So you probably want sth like this:

...
max_batch_id = JobStatus.objects.select_for_update(nowait=False).aggregate(Max(F('batch_id')))
...
Back to Top