Модели: таблицы как классы Python
Модель — это класс Python, описывающий таблицу: каждый атрибут становится столбцом. Один класс User — одна таблица users со столбцами id, name, email.
Модель — это схема таблицы на языке Python. В современном SQLAlchemy 2.x/Flask-SQLAlchemy 3.x столбцы объявляют типизированно через Mapped и mapped_column: тип столбца виден прямо в аннотации, а IDE подсказывает поля.
В прошлом уроке мы настроили db. Теперь опишем, что хранить. Модель наследует db.Model, а столбцы задаются современным типизированным синтаксисом: аннотация Mapped[тип] плюс mapped_column с параметрами.
from sqlalchemy.orm import Mapped, mapped_column
from .extensions import db
class User(db.Model):
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(db.String(80))
email: Mapped[str] = mapped_column(db.String(120), unique=True)
active: Mapped[bool] = mapped_column(default=True)
def __repr__(self):
return f"<User {self.name}>"
Разберём параметры: primary_key=True — уникальный идентификатор строки (обычно автоинкремент); unique=True — значение не повторяется (двух пользователей с одним email не будет); default — значение по умолчанию. Аннотация Mapped[str] говорит и Python, и SQLAlchemy, что столбец строковый и обязательный (а Mapped[str|None] — необязательный).
После описания моделей таблицы создаются один раз в контексте приложения:
with app.app_context():
db.create_all()
Типизированный синтаксис Mapped/mapped_column — это современный стандарт SQLAlchemy 2.x, и он стоит того, чтобы привыкнуть к нему сразу: тип столбца виден прямо в аннотации, IDE подсказывает поля и ловит опечатки, а Mapped[str] против Mapped[str | None] явно различает обязательные и необязательные столбцы. Отдельно стоит усвоить ограничение db.create_all: он создаёт только отсутствующие таблицы и не трогает существующие. Как только модель меняется на работающем проекте с данными, create_all бессилен — нужны миграции. Flask-Migrate поверх Alembic генерирует и применяет пошаговые изменения схемы, сохраняя данные. На учебном проекте можно стартовать с create_all, но привычку к миграциям лучше выработать рано.
Как работает под капотом
SQLAlchemy читает класс и его аннотации и строит из них определение таблицы — фактически генерирует SQL вида CREATE TABLE. db.create_all обходит все модели и создаёт недостающие таблицы.
class User: CREATE TABLE users (
id Mapped[int] PK ──▶ id INTEGER PRIMARY KEY,
name Mapped[str] ──▶ name VARCHAR(80) NOT NULL,
email unique ──▶ email VARCHAR(120) UNIQUE,
active default=True ──▶ active BOOLEAN DEFAULT 1
);
Смоделируем «класс → схема таблицы» обычным Python: соберём описание столбцов из определения модели.
class Column:
def __init__(self, type_, primary_key=False, unique=False):
self.type_ = type_
self.primary_key = primary_key
self.unique = unique
class User:
columns = {
"id": Column("INTEGER", primary_key=True),
"name": Column("VARCHAR(80)"),
"email": Column("VARCHAR(120)", unique=True),
}
def create_table_sql(model, name):
parts = []
for col, c in model.columns.items():
flags = " PRIMARY KEY" if c.primary_key else (" UNIQUE" if c.unique else "")
parts.append(f" {col} {c.type_}{flags}")
return f"CREATE TABLE {name} (\n" + ",\n".join(parts) + "\n);"
print(create_table_sql(User, "users"))
Запусти: из описания класса собрался SQL создания таблицы. SQLAlchemy делает это автоматически для каждой модели при db.create_all.
Частые ошибки
- Забыть primary_key. Каждой таблице нужен уникальный идентификатор строки.
- Менять модель и ждать, что таблица обновится сама. db.create_all не меняет существующие таблицы — для изменений схемы нужны миграции (Alembic/Flask-Migrate).
- create_all без app_context. Операции с базой требуют контекста приложения.
Best practices
- Используй типизированный синтаксис Mapped/mapped_column — он современнее и дружит с IDE.
- Для эволюции схемы подключай миграции (Flask-Migrate поверх Alembic), а не create_all.
- Добавляй __repr__ — упрощает отладку.
Что запомнить
- Модель — класс-описание таблицы; атрибуты становятся столбцами.
- Современный синтаксис: Mapped[тип] + mapped_column с параметрами.
- primary_key, unique, default задают ограничения и поведение столбца.
- create_all создаёт новые таблицы; для изменений схемы нужны миграции.
Итог: модель — это класс-описание таблицы с типизированными столбцами через Mapped/mapped_column; db.create_all генерирует таблицы. Дальше научимся читать и писать данные через сессию.