I was using Django 1.5.1 and upgraded to Django 1.6.6.
In Django 1.5.1 I was using select for update to guarantee atomic execution.
job_qs = Job.objects.select_for_update().filter(pk=job.id)
for job in job_qs:
Unfortunately this now throws an error:
File "/srv/venvs/django-picdoc/local/lib/python2.7/site-packages/django/db/models/query.py", line 96, in __iter__
self._fetch_all()
File "/srv/venvs/django-picdoc/local/lib/python2.7/site-packages/django/db/models/query.py", line 857, in _fetch_all
self._result_cache = list(self.iterator())
File "/srv/venvs/django-picdoc/local/lib/python2.7/site-packages/django/db/models/query.py", line 220, in iterator
for row in compiler.results_iter():
File "/srv/venvs/django-picdoc/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 713, in results_iter
for rows in self.execute_sql(MULTI):
File "/srv/venvs/django-picdoc/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 776, in execute_sql
sql, params = self.as_sql()
File "/srv/venvs/django-picdoc/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 147, in as_sql
raise TransactionManagementError("select_for_update cannot be used outside of a transaction.")
TransactionManagementError: select_for_update cannot be used outside of a transaction.
What are some of the solutions for solving this?
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 transaction
def some_method():
with transaction.atomic():
job_qs = Job.objects.select_for_update().filter(pk=job.id)
for job in job_qs:
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 inselect_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 inselect_for_update(of=(...))
using the same fields syntax asselect_related()
. Use the value 'self' to refer to the queryset’s model.
https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-for-update
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