Отношения таблиц
В SQLAlchemy отношения представляют собой связи между различными записями в базе данных. Понимание концепции взаимоотношений имеет решающее значение в качестве основы для эффективного проектирования и управления схемами баз данных. Связь в SQLAlchemy устанавливает связь между двумя таблицами в базе данных, позволяя данным из одной таблицы быть связаны с данными в другой таблице. Это позволяет запрашивать и извлекать связанные данные более эффективным и организованным образом, в конечном итоге экономя системные ресурсы.
В основе отображения отношений в SQLAlchemy лежат первичные и внешние ключи. Первичный ключ - это уникальный идентификатор для каждой записи в таблице, в то время как внешний ключ - это поле, которое ссылается на первичный ключ другой таблицы. Устанавливая связь с ключом, вы можете связать записи между таблицами, что позволяет ассоциировать и извлекать связанные данные. Отношения первичного ключа и внешнего ключа формируют основу для определения отношений в SQLAlchemy.
SQLAlchemy поддерживает различные типы отношений, каждый из которых служит различным целям и сценариям моделирования. Три основных типа отношений: один к одному, один ко многим и много к многим. Понимая фундаментальные концепции отношений, значение первичных и внешних ключей, а также различные типы отношений, вы будете лучше подготовлены для использования возможностей SQLAlchemy при определении и управлении отношениями в ваших веб-приложениях.
SQLAlchemy строго поддерживает различные типы отношений родитель-дочерний или ассоциативные таблицы. Классы моделей, участвующие в отношениях, требуют директивы relationship() из модуля sqlalchemy.orm, который будет использоваться для установления связей «один-ко-многим» или «один-к-одному» между классами моделей. Эта директива создает ссылку от родительского класса к дочернему классу, используя некоторый внешний ключ, указанный в определении схемы таблицы.
Один к одному
Отношения один к одному в SQLAlchemy представляют собой ассоциацию между двумя сущностями, где каждая запись в одной таблице связана ровно с одной записью в другой таблице, и наоборот. В отношениях один к одному первичный ключ одной таблицы служит ключом в другой таблице, устанавливая прямую связь между двумя сущностями. Этот тип отношений обычно используется, когда существует строгое соответствие один к одному между моделируемыми сущностями. Например, рассмотрим сценарий, в котором у вас есть таблица "Пользователей" и таблица "Профилей". У каждого пользователя есть один профиль, и каждый профиль принадлежит только одному пользователю. Это идеальный вариант использования для отношений один на один.
Чтобы реализовать отношения один к одному между моделями, нам необходимо определить отношения в соответствующих классах моделей:
from sqlalchemy.orm import relationship
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(50))
password = Column(String())
profile = relationship('Profile', uselist=False, back_populates='user')
class Profile(Base):
__tablename__ = 'profiles'
id = Column(Integer, primary_key=True)
full_name = Column(String(100))
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship('User', back_populates='profile')
В приведенном выше фрагменте кода отношение пользователя определяется в модели User с помощью функции relationship, указав имя другой модели и параметр uselist=False для обозначения отношения один к одному. Параметр back_populates обеспечивает двунаправленную навигацию, обеспечивая доступ к связанному объекту User из объекта Profile и от объекта User к объекту Profile. Поскольку в этом примере мы используем back_populates в отличие от backref, необходимо определить отношение с обеих сторон, в то время как с backref нам нужно будет определить отношение только с одной стороны (только в рамках одной модели).
Также мы можем написать эти модели, используя конструкцию SQLAlchemy 2.0 используя аннотации:
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(Integer(), primary_key=True)
username: Mapped[str] = mapped_column(String(50))
password: Mapped[str] = mapped_column(String())
profile: Mapped["Profile"] = relationship("Profile", backref="user")
class Profile(Base):
__tablename__ = 'profiles'
id: Mapped[int] = mapped_column(Integer(), primary_key=True)
full_name: Mapped[str] = mapped_column(String(50))
user_id: Mapped[int] = mapped_column(Integer(), ForeignKey('users.id'))
В результате мы получим следующие таблицы:
В следующем шаге мы рассмотрим другие отношения таблиц.
Тут uselist не нужно использовать?
profile: Mapped["Profile"] = relationship("Profile", backref="user")Вообще получается при использовании
back_populatesдостаточно только в одной модели прописатьuselist?@Dmitriy_Novozhilov, Тут это значение определяется автоматически когда мы используем Mapped.
Да, указывая как
back_populates, мы можем обращаться к зависимым таблицам с двух сторон, и соответственноuselistиспользуется в оба направления.