Короткий ответ
Модель описывается как Python-класс, наследующий от общей декларативной базы (Base), с атрибутами класса типа Mapped[...]/mapped_column, задающими колонки таблицы, их типы и ограничения; SQLAlchemy связывает класс с таблицей через атрибут __tablename__.
Как это работает подробнее
При объявлении класса SQLAlchemy регистрирует его в метаданных (MetaData), связывая имя таблицы, колонки и их типы; это описание используется и для генерации DDL (Base.metadata.create_all), и для построения SQL-запросов через ORM.
Пример кода
example.py
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
email: Mapped[str] = mapped_column(unique=True)
name: Mapped[str | None] = mapped_column(nullable=True)
# Base.metadata.create_all(engine) создаст таблицу users в БДЧто использовать на практике
- Практика. В современных версиях SQLAlchemy (2.0+) рекомендуется типизированный стиль Mapped[int]/mapped_column вместо старого Column, что даёт подсказки типов в IDE и явную поддержку Optional для nullable-колонок.
Подводные камни
- Ошибка. Забывают указать primary_key=True хотя бы на одной колонке, из-за чего SQLAlchemy не может идентифицировать строки для ORM-операций; путают __tablename__ (обязателен) с именем класса, предполагая автоматическое совпадение.