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
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() # 请求结束后自动关闭会话,防止连接泄漏
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")
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)
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("测试数据插入完成!")
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 写法对照
| 操作 | Django | Flask-SQLAlchemy | FastAPI(原生 SQLAlchemy) |
|---|---|---|---|
| 基类 | models.Model | db.Model | Base (DeclarativeBase) |
| 字段 | 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 |
本章小结
本章你掌握了 FastAPI 中的 SQLAlchemy 集成:create_engine + SessionLocal 配置数据库连接、DeclarativeBase 定义模型基类、get_db 依赖注入管理会话、Column/relationship 定义字段和关系。
与 Flask-SQLAlchemy 相比,原生 SQLAlchemy 写法稍多但完全开源可控。
