Django 1.5.1を使用していて、Django 1.6.6にアップグレードしました。
Django 1.5.1では、アトミックな実行を保証するために、更新にselectを使用していました。
job_qs = Job.objects.select_for_update().filter(pk=job.id)
for job in job_qs:
残念ながら、これでエラーが発生します。
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.
これを解決するための解決策のいくつかは何ですか?
答えはエラーです。クエリをトランザクションでラップします
Djangoのドキュメントは次の場所にあります: https://docs.djangoproject.com/en/dev/topics/db/transactions/#Django.db.transaction.atomic
1つのアプローチは次のとおりです。
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:
Django 2.0の時点では、関連する行はデフォルトでロックされ(以前の動作は不明)、ロックする行はof
を使用して_select_related
_と同じスタイルで指定できます。パラメータ:
デフォルトでは、
select_for_update()
はクエリによって選択されたすべての行をロックします。たとえば、クエリセットのモデルの行に加えて、select_related()
で指定された関連オブジェクトの行がロックされます。これが望ましくない場合は、select_for_update(of=(...))
と同じフィールド構文を使用して、select_related()
にロックする関連オブジェクトを指定します。クエリセットのモデルを参照するには、値「self」を使用します。
https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-for-update