Функция on_commit
Функция on_commit из модуля django.db.transaction
позволяет зарегистрировать callback-функцию, которая будет
выполнена только после успешной фиксации текущей транзакции.
Это полезно для выполнения действий, которые должны произойти
только после подтверждения изменений в базе данных, например,
отправка уведомлений, очистка кеша или вызов внешних API.
Если транзакция откатывается, зарегистрированные функции
не вызываются.
Синтаксис
from django.db import transaction
transaction.on_commit(callable, using=None)
Параметр callable - это функция или любой вызываемый
объект, который будет выполнен после фиксации транзакции.
Необязательный параметр using указывает псевдоним
подключения к базе данных, для которого регистрируется
обратный вызов.
Пример
Допустим, у нас есть модель статьи, и после сохранения новой статьи мы хотим отправить уведомление подписчикам, но только если статья действительно сохранена в базе данных:
from django.db import models, transaction
from myapp.models import Article
from myapp.tasks import send_notification
with transaction.atomic():
article = Article.objects.create(title="New Article", status="published")
transaction.on_commit(lambda: send_notification(article.id))
В этом примере функция send_notification будет вызвана
только после того, как транзакция успешно зафиксируется.
Если произойдет ошибка до фиксации, уведомление не будет
отправлено.
Пример
Рассмотрим ситуацию с несколькими вложенными транзакциями.
Функция on_commit выполняется только после фиксации
самой внешней транзакции:
from django.db import transaction
from myapp.models import Article
def cleanup_cache():
print("Cache cleared")
with transaction.atomic():
with transaction.atomic():
article = Article.objects.create(title="Draft Article")
transaction.on_commit(cleanup_cache)
# Функция будет выполнена только после
# фиксации внешней транзакции
Несмотря на то, что on_commit вызван внутри вложенной
транзакции, callback выполнится только после фиксации внешнего
блока atomic.
Пример
Если вам нужно выполнить действие сразу, если транзакция уже зафиксирована, или отложить его, если транзакция активна, можно использовать проверку состояния:
from django.db import transaction
from myapp.models import Category
def update_category_count():
count = Category.objects.count()
print(f"Total categories: {count}")
if transaction.get_connection().in_atomic_block:
transaction.on_commit(update_category_count)
else:
update_category_count()
В этом примере мы проверяем, находимся ли мы внутри
транзакционного блока. Если да - регистрируем callback
через on_commit, иначе выполняем функцию сразу.
Пример
on_commit также можно использовать с декоратором
transaction.atomic для более компактной записи:
from django.db import transaction
from myapp.models import Article
from myapp.services import index_article
@transaction.atomic
def create_article_and_index(title, content):
article = Article.objects.create(title=title, content=content)
transaction.on_commit(lambda: index_article(article.id))
return article
Функция index_article, которая, например, добавляет
статью в поисковый индекс, будет вызвана только после
успешного завершения всей транзакции в декорируемой функции.
Пример
Если вам нужно зарегистрировать несколько callback-функций, они будут выполнены в порядке регистрации:
from django.db import transaction
from myapp.models import Article
with transaction.atomic():
article = Article.objects.create(title="Final Article")
transaction.on_commit(lambda: print("First callback"))
transaction.on_commit(lambda: print("Second callback"))
transaction.on_commit(lambda: print("Third callback"))
Результат выполнения кода:
"First callback"
"Second callback"
"Third callback"