Событие after_commit
Событие after_commit относится к событиям
сессии Session и срабатывает в момент,
когда транзакция была успешно зафиксирована
в базе данных. Обработчик получает первым
параметром объект сессии session.
Событие удобно применять для отправки
уведомлений, сброса кеша, публикации
сообщений в очередь или запуска фоновых
задач, которые должны выполняться только
после реальной записи данных. В отличие от
события before_commit, обработчик
after_commit вызывается уже после того,
как транзакция стала видимой для других
соединений.
Синтаксис
from sqlalchemy import event
@event.listens_for(Session, 'after_commit')
def handler(session):
pass
Пример
Давайте создадим модель Article и
подпишемся на событие after_commit,
чтобы вывести сообщение после фиксации
транзакции:
from sqlalchemy import create_engine, event
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
text: Mapped[str]
status: Mapped[str]
num: Mapped[int]
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
@event.listens_for(Session, 'after_commit')
def on_after_commit(session):
print('transaction committed')
with Session(engine) as session:
article = Article(
title='article',
text='some text',
status='draft',
num=1
)
session.add(article)
session.commit()
Результат выполнения кода:
"transaction committed"
Пример
Событие after_commit можно применить
для сбора идентификаторов только что
сохраненных объектов. После фиксации
транзакции первичные ключи уже заполнены
базой данных:
from sqlalchemy import create_engine, event
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
text: Mapped[str]
status: Mapped[str]
num: Mapped[int]
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
committed_ids = []
@event.listens_for(Session, 'after_commit')
def collect_ids(session):
for obj in session.identity_map.values():
if isinstance(obj, Article):
committed_ids.append(obj.id)
with Session(engine) as session:
session.add_all([
Article(title='article 1', text='text 1', status='draft', num=1),
Article(title='article 2', text='text 2', status='draft', num=2)
])
session.commit()
print(committed_ids)
Результат выполнения кода:
[1, 2]
Пример
Иногда нужно, чтобы обработчик
after_commit выполнился только один
раз. Для этого можно снять подписку внутри
самого обработчика через event.remove:
from sqlalchemy import create_engine, event
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
text: Mapped[str]
status: Mapped[str]
num: Mapped[int]
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
def once_handler(session):
print('committed once')
event.remove(Session, 'after_commit', once_handler)
event.listen(Session, 'after_commit', once_handler)
with Session(engine) as session:
session.add(Article(title='article', text='text', status='draft', num=1))
session.commit()
with Session(engine) as session:
session.add(Article(title='article', text='text', status='draft', num=2))
session.commit()
Результат выполнения кода:
"committed once"
Смотрите также
-
событие
before_commit,
которое срабатывает перед фиксацией транзакции -
событие
after_rollback,
которое срабатывает после отката транзакции -
функцию
listens_for,
которая регистрирует обработчик события -
функцию
remove,
которая снимает обработчик события