Модели SQLAlchemy — проектирование таблиц базы данных
В этой главе вы научитесь определять модели данных с использованием нативного ORM SQLAlchemy и управлять сессиями базы данных через внедрение зависимостей FastAPI.
Почему в FastAPI нет встроенной ORM?
В Django есть встроенная ORM, а Flask рекомендует Flask-SQLAlchemy.
В FastAPI нет встроенной ORM — он хочет, чтобы вы выбрали наиболее подходящий инструмент,SQLAlchemy + Pydantic— лучшее сочетание, признанное сообществом.
(venv) $ pip install sqlalchemy
Настройте подключение к базе данных
Пример
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, DeclarativeBase
# Путь к файлу базы данных SQLite
SQLALCHEMY_DATABASE_URL = "sqlite:///./blog.db"
# Создание движка: check_same_thread — параметр, специфичный для SQLite
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
connect_args={"check_same_thread": False} # Специфично для SQLite: разрешить кросс-поточность
)
# Создание фабрики сессий
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# Базовый класс: все ORM-модели наследуются от него
class Base(DeclarativeBase):
pass
check_same_thread=False— это необходимая конфигурация для SQLite в FastAPI. По умолчанию SQLite не позволяет использовать одно и то же соединение в разных потоках, но в веб-приложениях каждый запрос может обрабатываться в отдельном потоке.
Внедрение зависимостей: get_db
Пример
from fastapi import Depends
def get_db():
"""Внедрение зависимостей FastAPI: создать независимую сессию базы данных для каждого запроса"""
db = SessionLocal()
try:
yield db # Используйте эту сессию во время запроса
finally:
db.close() # Автоматически закрывать сессию после завершения запроса, чтобы предотвратить утечки соединений
Depends(get_db)— это система внедрения зависимостей FastAPI, в которой функции маршрутов автоматически получают сессии базы данных через внедрение зависимостей.
Определите модели: Post и Category
Пример
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey
from sqlalchemy.orm import relationship
from datetime import datetime
from database import Base
class Category(Base):
"""Категория статьи"""
__tablename__ = "categories"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(50), unique=True, nullable=False)
slug = Column(String(50), unique=True, nullable=False)
# back_populates двунаправленная связь
posts = relationship("Post", back_populates="category")
class Post(Base):
"""Запись блога"""
__tablename__ = "posts"
id = Column(Integer, primary_key=True, index=True)
title = Column(String(200), nullable=False)
slug = Column(String(200), unique=True, nullable=False)
summary = Column(Text, default="")
content = Column(Text, nullable=False)
category_id = Column(Integer, ForeignKey("categories.id"), nullable=False)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# Двунаправленная связь с Category
category = relationship("Category", back_populates="posts")
В FastAPI используетсянативный SQLAlchemy(не из Flask-SQLAlchemy
db.Model). Обратите внимание на различия в импортах Column, наследовании Base и синтаксисе relationship. Таблица сравнения будет предоставлена позже.
Инициализировать таблицы базы данных
Пример
from fastapi import FastAPI
from database import engine, Base
from models import Category, Post # Убедитесь, что классы моделей импортированы, чтобы Base.metadata мог их распознать
app = FastAPI()
@app.on_event("startup")
def on_startup():
"""Автоматически создаёт таблицы базы данных при запуске приложения (только для разработки)"""
Base.metadata.create_all(bind=engine)
Позже мы переключимся на миграции Alembic (глава 6),create_allИспользуется только на этапе быстрого прототипирования.
Вставка тестовых данных
Вставка тестовых данных в скрипте Python:
Пример
from database import SessionLocal
from models import Category, Post
db = SessionLocal()
# Создать Category
py = Category(name="Python", slug="python")
css = Category(name="CSS", slug="css")
fastapi = Category(name="FastAPI", slug="fastapi")
db.add_all([py, css, fastapi])
db.commit()
# Создать статью
db.add_all([
Post(title="Полное руководство для начинающих по FastAPI", slug="fastapi-guide",
summary="Изучите FastAPI с нуля", content="<h2>Почему стоит выбрать FastAPI?</h2><p>...</p>",
category_id=fastapi.id),
Post(title="Корутины Python: объяснение", slug="python-coroutine",
summary="Разберитесь в asyncio", content=<h2>Что такое корутина?</h2><p>...</p>,
category_id=py.id),
Post(title="CSS Grid Layout в действии", slug="css-grid",
summary="Реализация адаптивного макета с помощью Grid", content="<h2>Введение в Grid</h2><p>...</p>",
category_id=css.id),
])
db.commit()
db.close()
print("Вставка тестовых данных завершена!")
Запуститеpython seed.py, вставьте 3 статьи в базу данных.
Сравнение синтаксиса ORM в четырёх фреймворках.
| Действие | Django | Flask-SQLAlchemy | FastAPI (нативный SQLAlchemy) |
|---|---|---|---|
| базовый класс | models.Model | db.Model | Base (DeclarativeBase) |
| Fields | models.CharField() | db.Column(...) | Column(...) |
| Внешний ключ | ForeignKey(to, on_delete) | db.ForeignKey('table.col') | ForeignKey('table.col') |
| Связь | Автоматическое обратное отношение | db.relationship + backref | relationship + back_populates |
| Сессия | Автоматическое управление | db.session | SessionLocal() + Depends |
Итоги главы
В этой главе вы освоили интеграцию SQLAlchemy в FastAPI: create_engine + SessionLocal для настройки подключения к базе данных, DeclarativeBase для определения базового класса модели, внедрение зависимости get_db для управления сессиями, а также Column/relationship для определения полей и связей.
По сравнению с Flask-SQLAlchemy, нативный SQLAlchemy требует немного больше кода, но полностью открыт и контролируем.
Другие расширения