Исключение FlushError
Исключение FlushError наследуется от
SQLAlchemyError
и возникает в момент вызова метода flush сессии,
когда SQLAlchemy не может корректно записать
находящиеся в сессии объекты в базу данных.
Чаще всего ошибка связана с нарушением состояния
объектов: например, когда в сессии оказываются
две разные записи с одним и тем же первичным
ключом, либо когда объект был удалён, но всё
ещё используется в отношениях.
Исключение принимает сообщение об ошибке
и, как правило, содержит в тексте описание
проблемы и подсказку по её устранению.
Обрабатывать его следует так же, как и другие
исключения SQLAlchemy, - через блок
try / except.
Синтаксис
from sqlalchemy.exc import FlushError
raise FlushError(statement, params, orig)
Пример
Давайте создадим две модели с одинаковым
первичным ключом и попробуем сбросить их
в сессию. Это классический случай, когда
возникает FlushError:
from sqlalchemy import create_engine, Integer, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.exc import FlushError
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(Integer, primary_key=True)
title: Mapped[str] = mapped_column(String)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
first = Article(id=1, title='article')
second = Article(id=1, title='article')
session.add(first)
session.add(second)
try:
session.flush()
except FlushError as err:
print('FlushError:', err)
Результат выполнения кода:
"FlushError: New instance <Article at 0x...> with identity key (<class 'Article'>, (1,), None) conflicts with persistent instance <Article at 0x...>"
Пример
Давайте рассмотрим случай, когда объект
удалён из сессии, но всё ещё используется.
При сбросе такого объекта SQLAlchemy
также поднимет FlushError:
from sqlalchemy import create_engine, Integer, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.exc import FlushError
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(Integer, primary_key=True)
title: Mapped[str] = mapped_column(String)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(id=1, title='article')
session.add(article)
session.flush()
session.delete(article)
try:
session.flush()
except FlushError as err:
print('FlushError:', err)
Результат выполнения кода:
"FlushError: Instance <Article at 0x...> is already pending deletion. Cannot flush it."
Пример
Давайте покажем, как корректно обработать исключение и откатить транзакцию, чтобы продолжить работу с сессией:
from sqlalchemy import create_engine, Integer, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.exc import FlushError
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(Integer, primary_key=True)
title: Mapped[str] = mapped_column(String)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
first = Article(id=1, title='article')
second = Article(id=1, title='article')
session.add(first)
session.add(second)
try:
session.flush()
except FlushError as err:
print('Handled:', err)
session.rollback()
article = Article(title='article')
session.add(article)
session.flush()
print('Saved id:', article.id)
Результат выполнения кода:
"Handled: New instance <Article at 0x...> with identity key (<class 'Article'>, (1,), None) conflicts with persistent instance <Article at 0x...>"
"Saved id: 1"
Смотрите также
-
класс
SQLAlchemyError,
который является базовым для всех исключений SQLAlchemy -
класс
StaleDataError,
который возникает при рассинхронизации данных в сессии -
класс
InvalidRequestError,
который сигнализирует о некорректном запросе к сессии -
класс
PendingRollbackError,
который возникает при работе с сессией после отката