Отношение One-to-Many в SQLAlchemy

Отношение "один ко многим" в SQLAlchemy ORM

Одним из основных преимуществ SQLAlchemy является её мощный и гибкий ORM (Object-Relational Mapping), который позволяет создавать и манипулировать данными в базе данных, используя Python-классы. Одним из наиболее часто используемых типов отношений в базах данных является отношение One-to-Many.

Что такое отношение One-to-Many

Отношение One-to-Many (один ко многим) описывает связь, при которой одна запись в таблице может быть связана с множеством записей в другой таблице. Например, один автор может написать множество книг, но каждая книга имеет только одного автора.

Реализация One-to-Many в SQLAlchemy

Моделирование

Для реализации отношения One-to-Many в SQLAlchemy используется комбинация relationship и ForeignKey. Рассмотрим пример:

from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

class Author(Base):
    __tablename__ = 'authors'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    books = relationship("Book", back_populates="author")

class Book(Base):
    __tablename__ = 'books'
    id = Column(Integer, primary_key=True)
    title = Column(String)
    author_id = Column(Integer, ForeignKey('authors.id'))
    author = relationship("Author", back_populates="books")

В этом примере каждый автор Author может иметь несколько книг Book, но каждая книга принадлежит только одному автору.

Добавление и запрос данных

engine = create_engine('sqlite:///books.db')
Base.metadata.create_all(engine)

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()

# Создание автора и книг
tolkien = Author(name="J.R.R. Tolkien")
tolkien.books = [Book(title="The Fellowship of the Ring"), Book(title="The Two Towers")]

session.add(tolkien)
session.commit()

# Запрос автора и его книг
author = session.query(Author).filter_by(name="J.R.R. Tolkien").one()
for book in author.books:
    print(book.title)

Определение backref

Вместо явного определения отношения с обеих сторон, вы можете использовать backref для создания двунаправленного отношения между двумя моделями с одной стороны:

class Book(Base):
    __tablename__ = 'books'
    id = Column(Integer, primary_key=True)
    title = Column(String)
    author_id = Column(Integer, ForeignKey('authors.id'))
    author = relationship("Author", backref="books")

Теперь у модели Author автоматически появится атрибут books, благодаря параметру backref.

Указание порядка сортировки

Если у вас есть необходимость автоматически сортировать связанные записи, вы можете использовать параметр order_by:

class Author(Base):
    # ...
    books = relationship("Book", order_by=Book.title, back_populates="author")

Управление каскадными операциями

Как упомянуто ранее, cascade позволяет управлять жизненным циклом дочерних объектов. Например, cascade="all, delete-orphan" гарантирует, что дочерние объекты будут удалены, если их родительский объект будет удален, и что любые "сироты" (объекты, которые больше не имеют родительского объекта) также будут удалены.

Использование lazy для определения стратегии загрузки

В SQLAlchemy вы можете определить, как и когда связанные объекты будут загружаться из базы данных. Вот некоторые из опций:

  • select (по умолчанию): связанные объекты загружаются при первом обращении.
  • joined: связанные объекты загружаются немедленно с использованием JOIN операции.
  • subquery: аналогично joined, но использует подзапрос.
  • dynamic: загрузка объектов происходит по мере необходимости и возвращает запрос, который можно дополнительно модифицировать.

Заключение

Отношение One-to-Many - основной строительный блок при моделировании баз данных. SQLAlchemy делает его реализацию простой и интуитивно понятной, предоставляя множество инструментов для эффективной работы с данными.

Содержание: