Событие after_bulk_update
Событие after_bulk_update срабатывает после
выполнения массового обновления записей. Такое
обновление выполняется методом update у объекта
Query и не проходит через обычные события
before_update и after_update, которые
работают только с отдельными объектами сессии. Событие
after_bulk_update позволяет перехватить момент
завершения массового обновления. Обработчик получает
объект Update, содержащий информацию о запросе
и количестве затронутых строк.
Синтаксис
from sqlalchemy import event
event.listen(Query, 'after_bulk_update', fn)
Пример
Давайте создадим модель и подпишемся на событие
after_bulk_update, чтобы вывести количество
обновлённых строк:
from sqlalchemy import create_engine, event
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.orm import Query
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
status: Mapped[str]
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
def after_bulk_update_handler(update_context):
print('updated rows:', update_context.rowcount)
event.listen(Query, 'after_bulk_update', after_bulk_update_handler)
with Session(engine) as session:
session.add_all([
Article(title='article 1', status='draft'),
Article(title='article 2', status='draft'),
Article(title='article 3', status='published'),
])
session.commit()
session.query(Article).filter(
Article.status == 'draft'
).update({'status': 'published'})
session.commit()
Результат выполнения кода:
"updated rows: 2"
Пример
Давайте рассмотрим объект Update, который
передаётся в обработчик события. У него есть атрибуты
rowcount и statement:
from sqlalchemy import create_engine, event
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.orm import Query
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
status: Mapped[str]
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
def after_bulk_update_handler(update_context):
print('rowcount:', update_context.rowcount)
print('statement:', update_context.statement)
event.listen(Query, 'after_bulk_update', after_bulk_update_handler)
with Session(engine) as session:
session.add_all([
Article(title='article 1', status='draft'),
Article(title='article 2', status='draft'),
])
session.commit()
session.query(Article).filter(
Article.status == 'draft'
).update({'status': 'published'})
session.commit()
Результат выполнения кода:
"rowcount: 2"
"statement: UPDATE articles SET status=? WHERE articles.status = ?"
Пример
Давайте используем event.remove, чтобы
отписаться от события после первого срабатывания:
from sqlalchemy import create_engine, event
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.orm import Query
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
status: Mapped[str]
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
def after_bulk_update_handler(update_context):
print('updated rows:', update_context.rowcount)
event.remove(Query, 'after_bulk_update', after_bulk_update_handler)
event.listen(Query, 'after_bulk_update', after_bulk_update_handler)
with Session(engine) as session:
session.add_all([
Article(title='article 1', status='draft'),
Article(title='article 2', status='draft'),
])
session.commit()
session.query(Article).filter(
Article.status == 'draft'
).update({'status': 'published'})
session.commit()
session.query(Article).filter(
Article.status == 'published'
).update({'status': 'archived'})
session.commit()
Результат выполнения кода:
"updated rows: 2"
Второе обновление уже не вызвало обработчик, так как
мы отписались от события через event.remove.
Смотрите также
-
событие
after_bulk_delete,
которое срабатывает после массового удаления -
функцию
listen,
которая подписывает обработчик на событие -
функцию
remove,
которая отписывает обработчик от события -
событие
after_update,
которое срабатывает после обновления отдельного объекта