Исключение AmbiguousForeignKeysError
Исключение AmbiguousForeignKeysError наследуется
от ArgumentError и возникает при попытке
автоматически определить связь между двумя таблицами,
когда между ними существует более одного внешнего
ключа. SQLAlchemy не может самостоятельно выбрать,
какой именно внешний ключ использовать для
построения отношения, поэтому выбрасывает это
исключение с требованием указать ключ явно через
параметр foreign_keys или primaryjoin.
Чаще всего исключение появляется при работе с
функцией relationship, когда две таблицы
связаны несколькими внешними ключами. Например,
таблица сообщений может содержать одновременно
идентификатор отправителя и идентификатор
получателя, оба ссылаются на таблицу пользователей.
Синтаксис
from sqlalchemy.exc import AmbiguousForeignKeysError
try:
# код, вызывающий ошибку
pass
except AmbiguousForeignKeysError as exc:
print(exc)
Пример
Давайте создадим две таблицы с двумя внешними
ключами и попробуем построить связь через
relationship без указания конкретного ключа:
from sqlalchemy import create_engine, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
author_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
editor_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
author = relationship('User')
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
При выполнении кода будет выброшено исключение
AmbiguousForeignKeysError, потому что между
таблицами articles и users существует
два внешних ключа:
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship Article.author - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.
Пример
Исправим ошибку, указав конкретный внешний ключ
через параметр foreign_keys:
from sqlalchemy import create_engine, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
author_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
editor_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
author = relationship('User', foreign_keys=[author_id])
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
print("tables created")
Результат выполнения кода:
"tables created"
Пример
Альтернативный способ - указать условие соединения
явно через параметр primaryjoin:
from sqlalchemy import create_engine, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
author_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
editor_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
author = relationship('User', primaryjoin='Article.author_id == User.id')
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
print("tables created")
Результат выполнения кода:
"tables created"
Смотрите также
-
исключение
ArgumentError,
родительский класс для ошибок аргументов -
исключение
NoForeignKeysError,
которое возникает при отсутствии внешних ключей -
исключение
NoReferencedTableError,
которое возникает при отсутствии связанной таблицы -
исключение
InvalidRequestError,
которое сигнализирует о некорректном запросе