web-dev-qa-db-ja.com

Django select_for_updateはトランザクション外では使用できません

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.

これを解決するための解決策のいくつかは何ですか?

11
Kingpin2k

答えはエラーです。クエリをトランザクションでラップします

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:
24
Kingpin2k

補遺

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

9
DylanYoung