5.4 Отношения таблиц в SQLAchemy
4 из 4 шагов пройдено

Отношения таблиц

В 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 используется в оба направления.

Получается чтобы связать 2 таблицы нам обязательно надо сделать 2 вещи?

1)  Выполнить связь 2 таблиц с relationship и указав в нем back_populates или backref 

2) Создать поле с внешним ключом и связью ForeignKey 

@Dmitriy_Novozhilov, чтобы связать, нам необходимо только поле с внешним ключом и связью ForeignKey.  А через back_populates или backref мы указываем с какой стороны и через какую переменную будем обращаться.