Связи и объединения
Моделируйте связанные таблицы
«Связи и объединения» — бесплатный урок Python Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Python Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Python Academy содержит 4 уроков всего.
Связанные таблицы
В реальных данных всё связано: у автора много книг, у заказа много позиций. SQLAlchemy описывает эти связи с помощью связей и внешних ключей.
# Author 1 --- many --- Book
# A foreign key on Book points back to Author
print('One-to-many is the most common link')Внешние ключи
Столбец внешнего ключа хранит первичный ключ связанной строки. Объявите его с помощью ForeignKey('table.column').
from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, mapped_column
# author_id: Mapped[int] = mapped_column(ForeignKey('authors.id'))
print('ForeignKey links child to parent')Определение родителя
Родительская модель использует relationship(), чтобы хранить коллекцию дочерних объектов.
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from typing import List
class Base(DeclarativeBase):
pass
class Author(Base):
__tablename__ = 'authors'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
books: Mapped[List['Book']] = relationship(back_populates='author')
print('Author.books holds related Book objects')Определение дочернего объекта
Дочерняя модель содержит столбец внешнего ключа и relationship(), указывающую обратно на родительский объект.
from sqlalchemy import ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
class Book(Base):
__tablename__ = 'books'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
author_id: Mapped[int] = mapped_column(ForeignKey('authors.id'))
author: Mapped['Author'] = relationship(back_populates='books')
print('Book.author points to its parent')back_populates
back_populates связывает две связи, поэтому изменение одной стороны автоматически отражается на другой.
# author.books.append(book) also sets book.author = author
# Both sides stay in sync automatically
print('back_populates keeps both sides consistent')Навигация по связям
После связывания Вы обращаетесь к связи как к обычным атрибутам: author.books — это список, а book.author — родительский объект.
# for book in author.books:
# print(book.title)
# print(book.author.name)
print('Navigate with plain attribute access')Построение графа
Добавляйте дочерние объекты в коллекцию родителя. Добавление родителя в сессию автоматически распространяется на дочерние объекты.
# a = Author(name='Rowling')
# a.books.append(Book(title='Book 1'))
# session.add(a)
# session.commit() # author and book both saved
print('Cascade saves the whole object graph')Неявные объединения
Обращение к book.author заставляет SQLAlchemy автоматически загрузить связанную строку (ленивая загрузка) в фоновом режиме.
# Accessing book.author runs a SELECT if not loaded yet
# This is lazy loading
print('Lazy loading fetches related rows on access')Явные объединения
Для фильтрации по нескольким таблицам используйте join() в запросе select. Это создаёт объединение SQL JOIN.
from sqlalchemy import select
# stmt = select(Book).join(Author).where(Author.name == 'Rowling')
# books = session.scalars(stmt).all()
print('join(Author) filters across the relationship')Упреждающая загрузка
Чтобы избежать множества небольших запросов, загрузите связанные строки заранее с помощью joinedload или selectinload.
from sqlalchemy import select
from sqlalchemy.orm import selectinload
# stmt = select(Author).options(selectinload(Author.books))
print('selectinload preloads children in one extra query')Связи многие-ко-многим
Для связей многие-ко-многим обе стороны соединяет промежуточная таблица. В relationship() используется secondary=, указывающее на неё.
# students <-> courses via a 'enrollments' association table
# courses: Mapped[List['Course']] = relationship(secondary=enrollments)
print('secondary= models many-to-many')Проверка
Проверьте свои знания о связях.
Повторение
Вы научились моделировать связанные таблицы.
ForeignKeyхранит связь в столбце дочерней моделиrelationship()вместе сback_populatesсоединяет обе стороны- Связями можно управлять как обычными атрибутами; ленивая загрузка получает данные при обращении
join()фильтрует данные из нескольких таблиц;selectinloadвыполняет упреждающую загрузку;secondary=обрабатывает связи многие-ко-многим
Часто задаваемые вопросы
Урок «Связи и объединения» бесплатный?
Да — полный текст урока «Связи и объединения» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Python Academy, подпишись на CoddyKit PRO. Курс Python Academy содержит 4 уроков всего.
Чему я научусь в уроке «Связи и объединения»?
Моделируйте связанные таблицы Ты практикуешь Python Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Python Academy?
Предыдущий опыт не требуется. Python Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Связи и объединения»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Python Academy?
Да. Каждый урок Python Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- SQLAlchemy Core и ORM
- Определение моделей
- Запросы через Session
- Связи и объединения