现在位置: 首页 > FastAPI 教程 > 正文

SQLAlchemy 模型 — 设计数据库表

本章你将学会用原生 SQLAlchemy ORM 定义数据模型,并通过 FastAPI 依赖注入管理数据库会话。


FastAPI 为什么不用自带 ORM?

Django 有内置 ORM,Flask 推荐 Flask-SQLAlchemy。

FastAPI 没有内置 ORM——它希望你选择最适合的工具,SQLAlchemy + Pydantic 是社区公认的最佳组合。

(venv) $ pip install sqlalchemy

配置数据库连接

实例

# 文件路径:database.py
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)

# Base 类:所有 ORM 模型继承自它
class Base(DeclarativeBase):
    pass

check_same_thread=False 是 SQLite 在 FastAPI 中的必要配置。默认情况下 SQLite 不允许跨线程使用同一连接,但在 Web 应用中每个请求可能在不同线程中处理。

依赖注入:get_db

实例

# 文件路径:database.py 追加
from fastapi import Depends

def get_db():
    """FastAPI 依赖注入:为每个请求创建独立的数据库会话"""
    db = SessionLocal()
    try:
        yield db          # 请求期间使用这个会话
    finally:
        db.close()        # 请求结束后自动关闭会话,防止连接泄漏

Depends(get_db) 是 FastAPI 的依赖注入系统,路由函数通过依赖注入自动获得数据库会话。


定义模型:Post 和 Category

实例

# 文件路径:models.py
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 写法的差异。后面会有对照表。


初始化数据库表

实例

# 文件路径:main.py 启动事件中创建表
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 迁移(第六章),create_all 仅在快速原型阶段使用。


插入测试数据

在 Python 脚本中插入测试数据:

实例

# 文件路径:seed.py(运行一次即可)
from database import SessionLocal
from models import Category, Post

db = SessionLocal()

# 创建分类
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 布局实战", 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 写法对照

操作DjangoFlask-SQLAlchemyFastAPI(原生 SQLAlchemy)
基类models.Modeldb.ModelBase (DeclarativeBase)
字段models.CharField()db.Column(...)Column(...)
外键ForeignKey(to, on_delete)db.ForeignKey('table.col')ForeignKey('table.col')
关系自动反向db.relationship + backrefrelationship + back_populates
会话自动管理db.sessionSessionLocal() + Depends

本章小结

本章你掌握了 FastAPI 中的 SQLAlchemy 集成:create_engine + SessionLocal 配置数据库连接、DeclarativeBase 定义模型基类、get_db 依赖注入管理会话、Column/relationship 定义字段和关系。

与 Flask-SQLAlchemy 相比,原生 SQLAlchemy 写法稍多但完全开源可控。