1. transaction.on_commit()
とは?
Djangoでデータベーストランザクションが 正常にコミットされた直後 に何か作業を実行したいときに使用する コールバック登録メソッド です。
from django.db import transaction
transaction.on_commit(my_function)
このコードを実行すると、現在のトランザクションが正常に終了した後に my_function()
が実行されます。
2. どのような状況で使用するか?
状況 | 使用可否 |
---|---|
DBに確実に保存が終わった後に何か実行したいとき | ✅ 適切 |
Celeryタスクをトランザクション後に実行したいとき | ✅ 適切 |
外部API呼び出し、キャッシュ更新など | ✅ 適切 |
トランザクションの外で呼び出し順序が重要でないとき | ❌ 不適切 |
3. 核心概念
on_commit()
は 「現在実行中のトランザクションがあるときのみ」 意味があります。- トランザクションがなければ、 コールバックは即時実行 されます!
4. 誤った例
def my_view(request):
def notify():
print("実行されました!")
transaction.on_commit(notify) # トランザクションがないため即時実行されます!
5. 正しい使用例
from django.db import transaction
def my_view(request):
with transaction.atomic():
post = Post.objects.create(...)
post.categories.add(...)
def translate():
translate_post.delay(post.id)
transaction.on_commit(translate)
上記の例では post
の作成およびカテゴリの追加がすべて完了した後にのみ translate()
が実行されます。
6. なぜ重要か?
多くの開発者が以下を混同します:
- ORMの
create()
,add()
は実際にはコミットされたわけではない - コミット前はすべて「論理的保存」状態
- Celeryタスクは別プロセスで実行されるため、
- コミット前に実行されると 不完全なデータ を参照することになります
7. Celeryとともに使う理想的な例
@shared_task
def post_finalize_task(post_id, categories, tags):
post = Post.objects.get(id=post_id)
with transaction.atomic():
for name in categories:
cat, _ = Category.objects.get_or_create(name=name)
post.categories.add(cat)
for name in tags:
tag, _ = Tag.objects.get_or_create(name=name)
post.tags.add(tag)
def schedule_translation():
translate_post.delay(post.id)
transaction.on_commit(schedule_translation)
この構造は、カテゴリ/タグの保存が確実に行われた後にのみ translate_post
タスクを実行することを保証します。
8. まとめ
概念 | 説明 |
---|---|
いつ実行される? | トランザクションが正常にコミットされた直後 |
失敗したら? | rollbackされると絶対に実行されない |
トランザクションが無ければ? | 即時実行される (注意!) |
使用場所 | with transaction.atomic() ブロック内 |
活用例 | Celeryタスクの実行、通知の送信、キャッシュの反映など |
9. Jesseのコメント
transaction.on_commit()
は単なる遅延実行ではありません。
トランザクションが成功した場合にのみ実行するという開発者の明確な意図表現 であり、
ORMと非同期処理をともに使用する際に、データ整合性を守るための必須ツールです。
Add a New Comment