Исключение ObjectDeletedError
Исключение ObjectDeletedError наследуется от класса StaleDataError
и возникает, когда ORM пытается выполнить UPDATE или DELETE
для строки, которой уже нет в базе данных. Это типичная ситуация
при параллельной работе нескольких сессий с одними и теми же данными.
Исключение не принимает дополнительных параметров при создании,
но содержит информацию об объекте и его состоянии на момент ошибки.
Чаще всего исключение появляется при вызове метода flush
или commit, когда SQLAlchemy пытается синхронизировать
состояние объекта с базой данных, но обнаруживает, что строка
уже удалена.
Синтаксис
from sqlalchemy.orm.exc import ObjectDeletedError
Пример
Давайте создадим объект, удалим его из базы данных напрямую, а затем попробуем изменить через ORM:
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
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]
Теперь выполним сценарий с удалением строки в обход ORM:
from sqlalchemy import create_engine, text
from sqlalchemy.orm import Session
from sqlalchemy.orm.exc import ObjectDeletedError
from models import Base, Article
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(
title='article',
text='some text',
status='draft',
num=1
)
session.add(article)
session.commit()
# delete row directly, bypassing ORM
session.execute(
text('DELETE FROM articles WHERE id = :id'),
{'id': article.id}
)
session.commit()
try:
article.title = 'updated article'
session.commit()
except ObjectDeletedError as e:
print('ObjectDeletedError:', e)
Результат выполнения кода:
"ObjectDeletedError: Instance '<Article at 0x...>' has been deleted, or its row is otherwise not present."
Пример
Давайте покажем, как перехватить исключение и корректно обработать ситуацию с удаленным объектом:
from sqlalchemy import create_engine, text
from sqlalchemy.orm import Session
from sqlalchemy.orm.exc import ObjectDeletedError
from models import Base, Article
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(
title='article',
text='some text',
status='published',
num=10
)
session.add(article)
session.commit()
# another session deletes the row
with Session(engine) as other:
other.execute(
text('DELETE FROM articles WHERE id = :id'),
{'id': article.id}
)
other.commit()
try:
article.status = 'archived'
session.commit()
except ObjectDeletedError:
print('Row was deleted by another session')
print('Recovering object state')
session.rollback()
Результат выполнения кода:
"Row was deleted by another session"
"Recovering object state"
Пример
Давайте посмотрим, как исключение возникает при удалении уже удаленного объекта:
from sqlalchemy import create_engine, text
from sqlalchemy.orm import Session
from sqlalchemy.orm.exc import ObjectDeletedError
from models import Base, Article
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(
title='article',
text='to be deleted',
status='draft',
num=5
)
session.add(article)
session.commit()
session.execute(
text('DELETE FROM articles WHERE id = :id'),
{'id': article.id}
)
session.commit()
try:
session.delete(article)
session.commit()
except ObjectDeletedError as e:
print('Caught:', type(e).__name__)
Результат выполнения кода:
"Caught: ObjectDeletedError"
Смотрите также
-
исключение
StaleDataError,
родительский класс для ObjectDeletedError -
исключение
SQLAlchemyError,
базовый класс всех исключений SQLAlchemy -
исключение
FlushError,
возникает при ошибках во время flush сессии -
исключение
DetachedInstanceError,
возникает при обращении к отсоединенному объекту