FastAPI + SQLAlchemy ORM 表关系
模型关系分为:一对一、一对多、多对多。 核心依赖:ForeignKey(数据库约束) + relationship(ORM 对象导航)。
一、一对一关系(One-to-One)
|
|
关键说明
ForeignKey 的作用
- 在数据库层面创建外键约束,将
user_extension.user_id关联到user.id。 - 保证参照完整性:插入或更新时,值必须存在于
user.id。 - SQLAlchemy 利用此外键配合
relationship实现对象导航。
一对一必须在外键列加
unique=True,否则无法保证“一个用户最多一个扩展”。
relationship 的作用
- 在 Python 对象层面建立关联,不对应数据库列。
uselist=False:表示返回单个对象(非列表),是区分一对一与一对多的关键。back_populates:实现双向关系。两端字段名必须互指,例如:User.user_extension↔User_Extension.user- 设置任一端,另一端自动同步。
使用示例
|
|
默认懒加载:访问
user.user_extension时才触发 SQL 查询。
二、一对多关系(One-to-Many)
|
|
关键说明
ForeignKey 的作用
- 位于“多”方(
Book表),指向“一”方(User.id)。 - 允许多个
Book指向同一个User。 - 不要加
unique=True,否则会变成一对一。
relationship 配置
| 端 | 类型注解 | 说明 |
|---|---|---|
| “一”端(User) | Mapped[List["Book"]] |
返回列表,默认 uselist=True |
| “多”端(Book) | Mapped["User"] |
返回单个对象 |
back_populates实现双向同步,类型注解必须与关系语义一致。
使用示例
|
|
三、多对多关系(Many-to-Many)
|
|
关键说明
何时使用 Table 或 Base 子类
- 使用
Table:关联表无额外字段(如book_tag只包含book_id和tag_id)。 - 使用
Base子类:关联表有额外字段(如created_at、weight),称为“关联对象模式”。
对于标准多对多,必须使用
Table+Column。原文若使用mapped_column是错误的,因为Table不接受MappedColumn。
secondary 参数
- 指定中间表,可传
Table对象(推荐)或表名字符串。 - SQLAlchemy 自动生成 JOIN 查询。
其他要点
Table必须使用Base.metadata,确保Base.metadata.create_all()能创建该表。back_populates非必需,但建议使用以支持双向导航。
复合主键与多对多关系的逻辑:
在多对多关系中,关联表 book_tag 使用 (book_id, tag_id) 作为复合主键,其作用是确保同一本书和同一个标签的组合只出现一次,而非限制整体为一对一。
每一行代表一个“书-标签”关联。
一本书可关联多个标签:(book1, tag1), (book1, tag2), (book1, tag3) → 合法。
一个标签可被多本书使用:(book1, tag1), (book2, tag1), (book3, tag1) → 合法。
但重复组合如 (book1, tag1) 出现两次 → 违反主键约束 不合法 因此,复合主键不破坏多对多语义,反而保证了关联的唯一性与一致性,是标准设计
也就是说book_id和tag_id是可重复的,但两者的组合不可重复
使用示例
|
|
目录
相关文章
Fastapi的alembic数据库迁移
来简单实验一下FastAPI + SQLAlchemy + alembic 的 数据库迁移,记录一下碰到的一些问题
2025-7-7
Fastapi的ORM初始化以及增删改查
来简单实验一下FastAPI + SQLAlchemy 的 异步ORM,主要是初始化建表以及数据增删改查
2025-7-4
Fastapi的中间件与依赖注入
来简单实验一下Fastapi的中间件与依赖注入,了解其含义、主要作用以及运行方式
2025-7-3
Fastapi的基础实验
来简单实验一下 Fastapi中基础内容,包括基础实现、多种参数、响应请求以及异常处理,其他内容后面会写
2025-7-2
Python 执行模型与并发体系
来理解一下 python中的进程、线程、协程、GIL锁以及异步同步
2025-12-1