目录
-
- 前言
- [1 ORM 概念](#1 ORM 概念)
-
- [主流 ORM 对比](#主流 ORM 对比)
- [2 SQLAlchemy 分层架构](#2 SQLAlchemy 分层架构)
- [3 环境安装 & 数据库准备](#3 环境安装 & 数据库准备)
- [4 基础配置文件](#4 基础配置文件)
- [5 定义 ORM 模型(一对多示例:部门 & 员工)](#5 定义 ORM 模型(一对多示例:部门 & 员工))
- [6 CRUD 增删改查完整示例](#6 CRUD 增删改查完整示例)
-
- [6.1 新增 Create](#6.1 新增 Create)
- [6.2 查询 Read](#6.2 查询 Read)
- [6.3 更新 Update](#6.3 更新 Update)
- [6.4 删除 Delete](#6.4 删除 Delete)
- [7 表关联关系详解](#7 表关联关系详解)
-
- [7.1 一对多 / 多对一(最常用)](#7.1 一对多 / 多对一(最常用))
- [7.2 一对一](#7.2 一对一)
- [7.3 多对多(中间表 Table)](#7.3 多对多(中间表 Table))
- [relationship 核心参数](#relationship 核心参数)
- [8 sqlacodegen 逆向生成模型(已有数据库自动生成类)](#8 sqlacodegen 逆向生成模型(已有数据库自动生成类))
-
- [8.1 安装工具](#8.1 安装工具)
- [8.2 代码自动生成模型](#8.2 代码自动生成模型)
- [9 本章总结](#9 本章总结)

前言
SQLAlchemy 是 Python 最成熟 ORM 框架,分为 Core 底层 SQL 表达式、ORM 对象映射两层。本章讲解引擎 / 会话、模型定义、增删改查、一对多 / 一对一 / 多对多关联、sqlacodegen 逆向生成模型,适配 FastAPI 项目。
1 ORM 概念
ORM(对象关系映射):数据库表 ↔ Python 类,行 ↔ 对象,无需手写原生 SQL,屏蔽 MySQL/PostgreSQL 数据库差异。
主流 ORM 对比
表格
| 工具 | 适用场景 |
|---|---|
| SQLAlchemy | 通用、复杂查询、FastAPI 同步首选 |
| Tortoise-ORM | 纯异步 FastAPI 项目 |
| Django ORM | 仅 Django 框架 |
| SQLModel | 简化版 SQLAlchemy+Pydantic |
2 SQLAlchemy 分层架构
- DBAPI:底层数据库驱动(pymysql/psycopg2)
- Core 层:Engine 引擎、连接池、SQL 表达式、字段类型
- ORM 层:对象映射、relationship 表关联
核心组件
- Engine:数据库连接入口,管理连接池
- Base:所有模型父类,统一管理表元数据
- Session:数据库会话,执行 CRUD、事务提交回滚
3 环境安装 & 数据库准备
bash
# ORM核心 + MySQL驱动
pip install sqlalchemy pymysql
提前创建 MySQL 数据库:create database fastapi_db charset utf8mb4;
4 基础配置文件
base.py(模型基类)
python
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
database.py(引擎、会话工厂)
python
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# 连接字符串格式 mysql+pymysql://账号:密码@地址:端口/库名
DB_URL = "mysql+pymysql://root:123456@localhost:3306/fastapi_db"
engine = create_engine(
DB_URL,
echo=True, # 开发打印SQL,生产关闭
pool_pre_ping=True # 自动检测失效连接
)
# 会话工厂,autocommit关闭必须手动commit
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
5 定义 ORM 模型(一对多示例:部门 & 员工)
python
from sqlalchemy import Column, Integer, String, Date, ForeignKey
from sqlalchemy.orm import relationship
from base import Base
# 部门表 一对多主表
class Department(Base):
__tablename__ = "departments"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False, unique=True)
location = Column(String(100))
# 一对多关联员工
employees = relationship("Employee", back_populates="department", lazy="selectin")
# 员工表 多对子表
class Employee(Base):
__tablename__ = "employees"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50), nullable=False)
age = Column(Integer)
hire_date = Column(Date)
# 外键关联部门
department_id = Column(Integer, ForeignKey("departments.id", ondelete="RESTRICT"), nullable=False)
# 反向关联部门,uselist=False单对象
department = relationship("Department", back_populates="employees", lazy="joined")
创建数据表
python
from base import Base
from database import engine
import models # 必须导入模型,否则无法识别表
def create_tables():
Base.metadata.create_all(bind=engine)
if __name__ == "__main__":
create_tables()
6 CRUD 增删改查完整示例
6.1 新增 Create
python
from database import SessionLocal
from models import Department, Employee
from datetime import date
db = SessionLocal()
try:
# 新增部门
dept = Department(name="研发部", location="北京总部")
db.add(dept)
db.commit()
db.refresh(dept) # 刷新获取自增id
# 批量新增员工
emp1 = Employee(name="张三", age=30, hire_date=date(2023,1,1), department_id=dept.id)
emp2 = Employee(name="李四", age=28, hire_date=date(2023,3,15), department_id=dept.id)
db.add_all([emp1, emp2])
db.commit()
except Exception as e:
db.rollback() # 异常回滚
finally:
db.close()
6.2 查询 Read
python
db = SessionLocal()
# 1.主键查询
dept = db.get(Department, 1)
# 2.条件过滤filter
emps = db.query(Employee).filter(Employee.department_id == 1).all()
# 3.多条件 and_ / or_
from sqlalchemy import and_, or_
emp = db.query(Employee).filter(and_(Employee.age>25, Employee.department_id==1)).first()
# 4.联表join查询
res = db.query(Employee, Department).join(Department, Employee.department_id == Department.id).all()
# 5.预加载关联数据,避免N+1查询
from sqlalchemy.orm import joinedload
emps = db.query(Employee).options(joinedload(Employee.department)).all()
6.3 更新 Update
python
db = SessionLocal()
emp = db.query(Employee).filter(Employee.name == "张三").first()
if emp:
emp.age = 31
db.commit()
6.4 删除 Delete
python
db = SessionLocal()
emp = db.query(Employee).filter(Employee.name == "李四").first()
if emp:
db.delete(emp)
db.commit()
7 表关联关系详解
7.1 一对多 / 多对一(最常用)
- 子表添加外键
ForeignKey - 主表
relationship返回列表,子表反向返回单个对象 back_populates双向关联,代码可读性优于 backref
7.2 一对一
- 子表外键添加
unique=True保证唯一 - 主表 relationship 添加
uselist=False,返回单个对象而非列表
7.3 多对多(中间表 Table)
python
from sqlalchemy import Table
# 中间表,无模型类
student_course = Table(
"student_course",
Base.metadata,
Column("student_id", Integer, ForeignKey("students.id"), primary_key=True),
Column("course_id", Integer, ForeignKey("courses.id"), primary_key=True)
)
# 模型中通过secondary绑定中间表
courses = relationship("Course", secondary=student_course, back_populates="students")
relationship 核心参数
back_populates:双向关联(推荐)cascade:级联操作all, delete-orphan删除主表同步删子表lazy加载策略:selectin批量加载避免 N+1,joined联表加载
8 sqlacodegen 逆向生成模型(已有数据库自动生成类)
8.1 安装工具
bash
pip install sqlacodegen pymysql
8.2 代码自动生成模型
python
import subprocess, sys
DB_URL = "mysql+pymysql://root:123456@localhost:3306/fastapi_db"
cmd = [sys.executable, "-m", "sqlacodegen", DB_URL]
result = subprocess.run(cmd, capture_output=True, text=True)
# 输出写入table_2_models.py
with open("table_2_models.py", "w", encoding="utf8") as f:
f.write(result.stdout)
适合遗留数据库项目,不用手动写模型字段
9 本章总结
- SQLAlchemy 三层架构:DBAPI→Core→ORM,Engine/Base/Session 三大核心
- CRUD 操作必须手动 commit,异常执行 rollback 事务回滚
- 表关联依靠外键 + relationship,合理配置 lazy 优化查询性能
- sqlacodegen 逆向生成模型,大幅节省已有数据库建模时间