Схема базы данных практикума
Все 20 задач работают с двумя связанными таблицами:
# Модели (SQLAlchemy 2.x, декларативный стиль)
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from sqlalchemy import String, Integer, ForeignKey
from typing import List, Optional
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(50))
age: Mapped[int] = mapped_column(Integer)
addresses: Mapped[List["Address"]] = relationship(
"Address", back_populates="user", cascade="all, delete-orphan"
)
class Address(Base):
__tablename__ = 'addresses'
id: Mapped[int] = mapped_column(primary_key=True)
description: Mapped[Optional[str]] = mapped_column(String(255))
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
user: Mapped["User"] = relationship("User", back_populates="addresses")
Примечание о session.query(): в задачах практикума используется
session.query() — это «legacy API», совместимый со всеми версиями SQLAlchemy. Новый стиль SQLAlchemy 2.x использует select() и session.execute(). Сравнение см. в Старый vs Новый.
Тестовые данные для практикума
Чтобы запросы возвращали результаты, нужны данные. Типичный набор:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
engine = create_engine('sqlite:///:memory:', echo=False)
Base.metadata.create_all(engine)
with Session(engine) as session:
users = [
User(name="Alice", age=25),
User(name="Bob", age=30),
User(name="Charlie", age=22),
User(name="Diana", age=35),
User(name="Eve", age=28),
]
session.add_all(users)
session.flush() # назначить id без commit
addresses = [
Address(description="Berlin", user=users[0]),
Address(description="Paris", user=users[1]),
Address(description="Berlin", user=users[2]),
Address(description="London", user=users[3]),
# users[4] (Eve) — без адреса
]
session.add_all(addresses)
session.commit()
Три группы задач
Блок 1: Базовые запросы (задачи 1–10)
Охватывают фундаментальные операции CRUD, сортировку и ограничения на количество результатов:
- Поиск (
.filter(),.first(),.all()) - Обновление (получить объект → изменить поле →
commit()) - Добавление (
session.add()+commit()) - Удаление (
session.delete()+commit()) - Сортировка (
order_by()), ограничение (limit()) - Поиск по id (
session.get()) - Проверка существования (
.exists())
Блок 2: Агрегации (задачи 11–15)
Используют func из sqlalchemy:
func.avg()— среднее значениеfunc.max()/func.min()— максимум/минимумfunc.count()+group_by()— группировка с подсчётомhaving()— фильтрация по результатам агрегацииsubquery()— вложенный запрос как источник данных
Блок 3: Связи и JOIN (задачи 16–20)
Работа с отношением User–Address:
join()— INNER JOIN (только пользователи с адресами)outerjoin()— LEFT OUTER JOIN (включая пользователей без адресов)- Фильтрация по полям связанной таблицы
- Обновление адреса через атрибут
user.addresses[0]