Функция foreign
Функция foreign помечает колонку как
внешний ключ для связи между таблицами.
Она используется внутри функции relationship
в параметрах primaryjoin и foreign_keys,
когда нужно явно указать, какая именно колонка
является ссылающейся стороной отношения.
Функция принимает один параметр - колонку,
которую следует пометить как внешнюю.
Возвращает объект ForeignKey, который
SQLAlchemy использует при построении условия
соединения таблиц.
Синтаксис
foreign(column)
Пример
Давайте создадим две модели, связанные отношением
один-ко-многим, и явно укажем внешний ключ через
foreign в параметре primaryjoin:
from sqlalchemy import create_engine, ForeignKey, String, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, foreign
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(50))
articles: Mapped[list['Article']] = relationship(
primaryjoin='User.id == foreign(Article.user_id)'
)
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with engine.connect() as conn:
pass
Здесь foreign явно помечает колонку
Article.user_id как внешнюю сторону отношения,
что позволяет SQLAlchemy правильно построить join.
Пример
Давайте заполним таблицы данными и проверим работу
связи, созданной через foreign:
from sqlalchemy import create_engine, ForeignKey, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, foreign, Session
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(50))
articles: Mapped[list['Article']] = relationship(
primaryjoin='User.id == foreign(Article.user_id)'
)
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
user = User(name='user')
user.articles = [
Article(title='article 1'),
Article(title='article 2'),
]
session.add(user)
session.commit()
res = session.execute(select(User)).scalar_one()
print([a.title for a in res.articles])
Результат выполнения кода:
['article 1', 'article 2']
Пример
Давайте используем foreign в параметре
foreign_keys, когда в модели несколько
колонок ссылаются на одну и ту же таблицу:
from sqlalchemy import create_engine, ForeignKey, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, foreign
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(50))
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
author_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
editor_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
author: Mapped['User'] = relationship(
foreign_keys=[author_id],
primaryjoin='User.id == foreign(Article.author_id)'
)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with engine.connect() as conn:
pass
Здесь модель Article содержит две колонки
с внешними ключами на таблицу users,
и foreign помогает однозначно определить,
какая из них используется в конкретном отношении.
Смотрите также
-
функцию
relationship,
которая настраивает связи между моделями -
функцию
remote,
которая помечает колонку как удаленную сторону отношения -
функцию
backref,
которая создает обратную ссылку в отношении -
функцию
joinedload,
которая жадно загружает связанные объекты через JOIN