Django select_for_update cannot be used outside of a transaction Django select_for_update cannot be used outside of a transaction django django

Django select_for_update cannot be used outside of a transaction


The answer is in the error, wrap the query in a transaction

Django's documentation is located here: https://docs.djangoproject.com/en/dev/topics/db/transactions/#django.db.transaction.atomic

One approach is:

from django.db import transactiondef some_method():       with transaction.atomic():      job_qs = Job.objects.select_for_update().filter(pk=job.id)      for job in job_qs:


Addendum

As of Django 2.0, related rows are locked by default (not sure what the behaviour was before) and the rows to lock can be specified in the same style as select_related using the of parameter:

By default, select_for_update() locks all rows that are selected by the query. For example, rows of related objects specified in select_related() are locked in addition to rows of the queryset’s model. If this isn’t desired, specify the related objects you want to lock in select_for_update(of=(...)) using the same fields syntax as select_related(). Use the value 'self' to refer to the queryset’s model.

https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-for-update


For me it happened even when using with transaction.atomic():. The problem was that we didn't set 'ATOMIC_REQUESTS': True in the settings.py file. Now this solved the problem.

As documented here: https://docs.djangoproject.com/en/3.1/topics/db/transactions/

"Set ATOMIC_REQUESTS to True in the configuration of each database for which you want to enable this behavior."

So in settings.py we added:

DATABASES = {    'default': {        'ENGINE': 'django.db.backends.mysql',        'NAME': os.environ['DB_NAME'],        'USER': os.environ['DB_USER'],        'PASSWORD': os.environ['DB_PASSWORD'],        'HOST': os.environ['DB_HOST'],        'PORT': '3306',        'ATOMIC_REQUESTS': True    }}