1. transaction.on_commit()
что это?
Это метод регистрации обратного вызова, который используется, когда необходимо выполнить какую-либо операцию сразу после успешного завершения транзакции в Django.
from django.db import transaction
transaction.on_commit(my_function)
Когда этот код выполняется, my_function()
будет вызвана после успешного завершения текущей транзакции.
2. В каких ситуациях используется?
Ситуация | Использовать? |
---|---|
Когда нужно что-то выполнить сразу после завершения сохранения в БД | ✅ Подходит |
Когда нужно выполнить задачу 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)
В данном примере translate()
будет выполнен только после успешного создания post
и добавления категорий.
6. Почему это важно?
Многие разработчики путают следующее:
create()
,add()
ORM фактически не являются завершёнными коммитами- До коммита все в состоянии "логического сохранения".
- Задачи 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. Итоговый обзор
Понятие | Описание |
---|---|
Когда выполняется? | Сразу после успешного завершения транзакции |
При неудаче? | Никогда не выполняется при откате |
Если транзакции нет? | Выполняется немедленно (внимание!) |
Где использовать? | Внутри блока with transaction.atomic() |
Примеры использования | Выполнение задач Celery, отправка уведомлений, обновление кэша и т.д. |
9. Комментарий Джесси
transaction.on_commit()
— это не просто отложенное выполнение.
Это четкое выражение намерения разработчика выполнять код только в случае успешного завершения транзакции, и это необходимый инструмент для поддержания целостности данных при использовании ORM и асинхронной обработки.
댓글이 없습니다.