Исключение IdentifierError
Исключение IdentifierError наследуется от
SQLAlchemyError
и возникает, когда ORM не может определить
значение первичного ключа для объекта. Чаще
всего это связано с попыткой сохранить
сущность, у которой не задан первичный ключ
и отсутствует автоматическая генерация
значения. Ошибка сигнализирует о нарушении
логики маппинга, а не о проблемах соединения
с базой данных.
В большинстве случаев IdentifierError
поднимается при вызове метода flush,
когда SQLAlchemy пытается сформировать
INSERT и обнаруживает, что значение
первичного ключа не может быть получено
ни из атрибутов объекта, ни из автоинкремента
колонки.
Синтаксис
from sqlalchemy.exc import IdentifierError
Пример
Давайте рассмотрим ситуацию, в которой
возникает исключение IdentifierError.
Определим модель Article с первичным
ключом без автоинкремента и попробуем
сохранить объект без явного указания
значения id:
from sqlalchemy import create_engine, Integer, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.exc import IdentifierError
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=False)
title: Mapped[str] = mapped_column(String)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(title='article')
session.add(article)
try:
session.flush()
except IdentifierError as exc:
print('IdentifierError:', exc)
Результат выполнения кода:
"IdentifierError: (sqlalchemy.exc.IdentifierError) ..."
Пример
Чтобы избежать исключения, достаточно явно задать значение первичного ключа перед добавлением объекта в сессию:
from sqlalchemy import create_engine, Integer, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy import select
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=False)
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()
res = session.execute(select(Article)).scalars().all()
print([(a.id, a.title) for a in res])
Результат выполнения кода:
[(1, 'article')]
Пример
Альтернативное решение - включить
автоинкремент у колонки первичного ключа,
тогда SQLAlchemy сам сгенерирует значение
id при вставке:
from sqlalchemy import create_engine, Integer, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy import select
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
title: Mapped[str] = mapped_column(String)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(title='article')
session.add(article)
session.flush()
res = session.execute(select(Article)).scalars().all()
print([(a.id, a.title) for a in res])
Результат выполнения кода:
[(1, 'article')]
Смотрите также
-
исключение
SQLAlchemyError,
которое является базовым для всех ошибок SQLAlchemy -
исключение
FlushError,
которое возникает при проблемах во время flush -
исключение
InvalidRequestError,
которое сигнализирует о некорректном запросе -
исключение
UnmappedInstanceError,
которое возникает при работе с немаппированным объектом