Ответ
Функция transaction.on_commit() в Django позволяет зарегистрировать колбэк (функцию), который будет выполнен только после успешного завершения (коммита) текущей транзакции в базе данных.
Это критически важно для выполнения действий, которые не должны происходить, если транзакция откатится. Основной сценарий использования — запуск фоновых задач, отправка уведомлений или вызов внешних API.
Почему это важно?
Представьте, что вы отправляете приветственное письмо сразу после создания пользователя. Если после отправки письма в транзакции произойдет ошибка и создание пользователя откатится, пользователь получит письмо, хотя его аккаунт не существует. on_commit решает эту проблему.
Пример:
from django.db import transaction
from .tasks import send_welcome_email
def create_user_and_send_email(username, email):
# Начало транзакции (неявно, если ATOMIC_REQUESTS=True, или явно)
user = User.objects.create(username=username, email=email)
# Регистрируем задачу, которая выполнится только после коммита
transaction.on_commit(lambda: send_welcome_email.delay(user.id))
# ... другие операции в рамках транзакции
# Если здесь произойдет ошибка, on_commit() не будет вызван.
Ключевые особенности:
- Гарантия выполнения: Код выполняется только если транзакция успешно зафиксирована в БД.
- Изоляция: Позволяет отделить логику работы с БД от побочных эффектов (side effects).
- Тестирование: Для корректной работы в тестах требует использования
django.test.TestCase, который оборачивает каждый тест в транзакцию.
Ответ 18+ 🔞
А, слушай, смотри, это же про transaction.on_commit() в Джанге! Ну, это такая штука, блядь, которая позволяет тебе прицепить какую-нибудь функцию, чтобы она выполнилась только после того, как вся текущая транзакция в базе данных успешно завершится.
Это, сука, архиважно, когда тебе надо что-то сделать, что не должно случиться, если вдруг вся эта кухня с данными откатится нахуй. Типа, запустить фоновую задачу, отправить письмо или дернуть какой-нибудь внешний API.
Ну и зачем это, блядь, вообще нужно?
Представь себе, ты создаёшь пользователя и сразу же, сраный оптимист, отправляешь ему приветственное письмо. А потом, блядь, в транзакции где-то дальше вылезает ошибка, всё откатывается, пользователя в базе нет, а письмо-то уже улетело! Человек получит письмо, а зарегаться не сможет, пиздец. Вот on_commit как раз от таких лютых косяков и спасает.
Вот смотри, как это выглядит:
from django.db import transaction
from .tasks import send_welcome_email
def create_user_and_send_email(username, email):
# Тут у нас транзакция начинается (сама, если ATOMIC_REQUESTS=True, или ты её явно обернул)
user = User.objects.create(username=username, email=email)
# А вот тут мы регистрируем задачу, которая пойдёт в работу ТОЛЬКО если всё закоммитится
transaction.on_commit(lambda: send_welcome_email.delay(user.id))
# ... а тут дальше можешь ещё какую-нибудь хуйню в рамках транзакции делать
# И если тут что-то пойдёт не так, то `on_commit` не выстрелит, и письмо не улетит!
Главные фишки, блядь:
- Железная гарантия: Твой код выполнится только если транзакция прошла успешно, и данные реально легли в базу. Иначе — ни хуя.
- Изоляция: Позволяет красиво отделить основную бизнес-логику работы с базой от всяких побочных эффектов, которые могут наебнуться.
- Тестирование: Тут, сука, внимание! Чтобы это в тестах работало как надо, нужно использовать
django.test.TestCase. Он каждый тест в транзакцию заворачивает, иначе можно охуеть от неожиданных результатов.