@seclink: 分享新文章 《基于 fastapi + SQLAlchemy ORM 的应用,有必要修改为基于 fastapi + sqlmodel 吗?》 https://juejin.cn/post/7648902852933304360…
摘要
该文章对比了FastAPI+SQLAlchemy与SQLModel的使用场景,分析了迁移的收益与成本,建议存量项目不必全量迁移。
查看缓存全文
缓存时间: 2026/06/09 14:54
分享新文章 《基于 fastapi + SQLAlchemy ORM 的应用,有必要修改为基于 fastapi + sqlmodel 吗?》 https://juejin.cn/post/7648902852933304360…
基于 fastapi + SQLAlchemy ORM 的应用,有必要修改为基于 fastapi + sqlmodel 吗?
Source: https://juejin.cn/post/7648902852933304360 在 Python Web 开发(尤其是 FastAPI + SQLAlchemy 生态)中,Models和Schemas是两个经常被提及但职责完全不同的概念。
简单来说:Models 负责“如何把数据存在数据库”,而 Schemas 负责“如何对 API 输入输出的数据进行校验和过滤”。
一、 核心概念对比
维度Models (数据库模型 / 实体)Schemas (校验模型 / DTO)主要定位****数据持久化(Database Persistence)****数据传输与边界校验(Validation & DTO)****代表框架SQLAlchemy, Tortoise-ORM, Django ORMPydantic, Marshmallow存在区域数据库的**表结构(Table Schema)**映射。API 接口的输入参数(Request)和输出数据(Response)。核心职责- 映射表名、主键、外键、索引
-
处理数据库关联关系 (Relationship)
-
执行 SQL 读写
-
验证字段类型、长度、格式(如 Email、手机号)
-
过滤敏感数据(如隐藏密码字段)
-
序列化为 JSON / 反序列化
二、 用一个生动的比喻来理解
假设你在开一家高端私人会所(系统):
- Models 是“会所内部的员工档案”:- 里面记录了员工的身份证号、真实姓名、家庭住址、合同编号、银行卡号(相当于数据库中的所有敏感和物理字段)。 - 这个档案只有经理(数据库/ORM)能看,绝对不能展示给客人。
- Schemas 是“员工的工作胸牌”:- 胸牌上只写着:艺名(Nick Name)、工作岗位(只暴露客人需要看到的信息)。 - 另外,客人要入会时,需要填一张“入会申请表”(输入 Schema),胸牌制作前需要检查格式对不对(数据校验)。
三、 数据流向图(它们在系统中的位置)
在一次完整的 API 请求中,它们各自站岗在不同的关口:
📥 [客户端请求 (JSON)]
│
▼
┌──────────────────────┐
│ Schemas (Pydantic) │ <--- 1. 拦截并校验数据(如:密码是否够长?Email 格式对吗?)
└──────────────────────┘
│ (验证通过,转换为 Python 对象)
▼
┌──────────────────────┐
│ Service / Controller │ <--- 2. 业务处理
└──────────────────────┘
│ (转换为 DB Model 对象)
▼
┌──────────────────────┐
│ Models (SQLAlchemy) │ <--- 3. 映射为数据库表的一行,写入数据库
└──────────────────────┘
│
▼
💾 [数据库 (DB)]
四、 代码实例对比
1. Models 的写法 (以 SQLAlchemy 为例)
它关注的是底层数据库的细节。
# app/models/user.py
from sqlalchemy import Column, Integer, String, Boolean
from app.database import Base
class DBUser(Base):
__tablename__ = "users" # 物理表名
id = Column(Integer, primary_key=True, index=True) # 数据库主键
email = Column(String, unique=True, index=True, nullable=False)
hashed_password = Column(String, nullable=False) # 数据库存的是哈希密文
is_active = Column(Boolean, default=True)
2. Schemas 的写法 (以 Pydantic 为例)
它关注的是 API 的输入和输出。
# app/schemas/user.py
from pydantic import BaseModel, EmailStr, Field
# 客户端注册时发送的数据(输入 Schema)
class UserCreate(BaseModel):
email: EmailStr # 自动验证必须是合法的邮箱格式
password: str = Field(min_length=8) # 强制要求密码至少 8 位
# 返回给客户端的数据(输出 Schema / DTO)
class UserResponse(BaseModel):
id: int
email: EmailStr
# 🚫 注意:这里绝对不能写 password 或 hashed_password
# 这样可以确保敏感的密码信息永远不会通过 API 泄漏给前端
五、 为什么 SQLModel 能把两者合二为一?
因为在传统开发中,DBUser和UserResponse存在大量的字段重复(比如id、email),修改一个字段要改两个文件。
SQLModel巧妙地通过 Python 的多重继承,让一个类同时扮演这两个角色:
- 当它带上
table=True时,它是Model(生成数据库表)。 - 当它不带
table=True时,它是Schema(进行 API 验证和过滤)。
对于一个已经使用FastAPI + SQLAlchemy ORM稳定运行的存量项目,通常没有绝对的必要进行全量重构去升级为 SQLModel。
尽管 SQLModel 带来了极佳的开发体验,但全量迁移的重构成本和潜在风险往往会大于它带来的直接收益。
以下是关于迁移收益、成本/风险以及决策建议的深度对比分析:
一、 迁移至 SQLModel 的核心收益(Why do it?)
如果选择迁移,你将获得以下三个最显著的“爽点”:
1. 消除双重定义,代码量减半(DRY - Don’t Repeat Yourself)
- 现状 (SQLAlchemy):新增一个表字段,你需要修改
models\.py(SQLAlchemy)、schemas\.py(UserCreate)、schemas\.py(UserResponse),很容易漏改。 - SQLModel:你只需要在
BaseModel中加一行,数据库迁移和 API 的输入输出校验将自动同步生效。
2. 完美的 IDE 自动补全与类型安全(Developer Experience)
- 现状 (SQLAlchemy):执行
db\.execute\(select\(User\)\)拿到的是Result,必须通过\.scalars\(\)\.all\(\)转换,且 IDE (VSCode/PyCharm) 经常无法推导出返回列表里是User实体,导致写后续代码时没有属性提示。 - SQLModel:
db\.exec\(select\(User\)\)\.all\(\)会被 IDE 精准识别为list\[User\],从查询到字段访问,全流程补全体验极佳。
3. 与 FastAPI 的原生无缝契合
- SQLModel 是由 FastAPI 作者 Tiangolo 亲自开发的。SQLModel 实例可以直接当做 FastAPI 的
response\_model返回,或者直接作为 Request Body 接收,省去了大量BaseModel\.model\_validate\(db\_obj\)的转换步骤。
二、 迁移的成本与潜在风险(The Cost & Risk)
1. 高级 ORM 特性的适配风险
SQLModel 底层虽然就是 SQLAlchemy,但它对一些复杂的 SQLAlchemy 高级特性进行了封装。如果你的项目大量使用了以下特性,迁移时会遇到不少阻力:
- 多表继承(如
Joined Table Inheritance、Polymorphic Queries)。 - 复杂的复合主键/外键关联。
- 高度自定义的
relationship属性(如自定义的 association proxy,或非标准的 join 条件)。 - 在这些场景下,SQLModel 可能会出现类型系统冲突,或者迫使你不得不退化到写
sa\_column=Column\(\.\.\.\),从而失去了 SQLModel 原有的简洁性。
2. 存量代码的工作量与测试回归
- 修改表定义:所有继承
declarative\_base\(\)的模型必须重构为继承SQLModel\(table=True\),所有的Column字段要改写为Field。 - 修改查询语句:虽然旧的 SQLAlchemy 查询(
db\.execute\(\.\.\.\))在 SQLModel 依然兼容,但为了类型安全,你可能需要将它们逐步改写为db\.exec\(\.\.\.\)。 - Alembic 迁移脚本:已经生成的数据库迁移脚本(Migrations)在模型基类变更后,需要小心处理,避免 Alembic 误判为表被删除重建。
三、 决策矩阵:怎么选?
项目状态建议决策理由与落地策略新建项目 / 微服务🚀果断使用 SQLModel没有任何历史包袱,能够完全享受 SQLModel 带来的极速开发体验。中小型存量项目
(模型数 < 15 个,表结构简单)⚖️可以考虑迁移重构时间在 1-2 天内可控,能够彻底消除冗余代码,提升后续维护效率。中大型企业级项目
(表结构复杂,高度依赖 SQL 优化)🛑维持 SQLAlchemy 现状****安全第一。SQLAlchemy 的生态更成熟,工业级排坑经验多。重构引入的回归 Bug 风险远大于 SQLModel 带来的语法糖收益。希望局部优化🛠️混合使用 (不冲突)**推荐。因为 SQLModel 底层是 SQLAlchemy,它的Session兼容普通的 SQLAlchemy Model。你可以在现有项目中,对新开发的模块**使用 SQLModel,存量模块保持不变,逐步过渡。### 💡 最终建议
- 如果当前项目运行稳定,且没有频繁的模型变更需求,不要修改。
- 如果你们正饱受“API DTO 与 数据库 Model 字段不同步”以及“IDE 没有 SQL 提示”的折磨,可以先挑选一个非核心的子业务模块进行SQLModel 局部重构,验证效果后再决定是否全面铺开。
将**底层的原生驱动(psycopg2)与高层 ORM(SQLAlchemy / SQLModel)进行对比,本质上是在“极致性能与精细控制”与“开发效率与工程可维护性”**之间做权衡。
以下是两者的优缺点深度对比:
相比于 直接用 psycopg2 , 使用 fastapi + SQLAlchemy ORM 或者 fastapi + sqlmodel 有什么优缺点 ?
一、 直接使用psycopg2(原生驱动)
psycopg2是 PostgreSQL 的底层 C 语言驱动,直接执行原生 SQL。
优点:
- 极致的性能(Zero Overhead):没有 ORM 框架在中间做“SQL 转换”和“对象实例化(Row -> Python Object)”的开销。性能几乎达到 Python 操作 PostgreSQL 的物理极限。
- 完全掌控 SQL:你可以写任意复杂的 PostgreSQL 特有语法(如窗口函数、递归 CTE、JSONB 操作、全文检索等),不用去研究 ORM 对应的怪异语法。
- 更轻量:项目依赖少,启动速度快,没有复杂的 ORM 状态管理(如 Session 状态、延迟加载等带来的坑)。
缺点:
- 开发效率极其低下:简单的增删改查(CRUD)也必须手写完整的 SQL 语句,并手动处理占位符(如
%s)以防 SQL 注入。 - 缺乏类型安全与自动补全:SQL 是以字符串(string)形式写在代码里的,IDE(如 VSCode/PyCharm)无法对 SQL 字符串内的字段做语法检查、自动补全或重构。
- 手动结果集转换(ResultSet Mapping):
psycopg2默认返回的是元组列表(list\[tuple\])或字典(dict)。你必须自己写代码把它们解析并映射成 Python 对象或 JSON,极易出错。 - 同步阻塞(与 FastAPI 冲突):
psycopg2是同步阻塞的驱动。在 FastAPI 的异步事件循环中,如果直接执行慢查询,会阻塞整个服务。虽然可以通过多线程或换用psycopg3/asyncpg解决,但增加了开发复杂度。
二、 使用FastAPI \+ SQLAlchemy / SQLModel(高层 ORM)
优点:
- 极高的开发效率:提供面向对象的操作方式。例如创建一条记录只需
db\.add\(user\);查询只需select\(User\),无需编写繁琐的 INSERT/UPDATE 语句。 - 自动数据校验与序列化(配合 Pydantic):- 输入:FastAPI 自动将前端 JSON 校验并转换为 Pydantic/SQLModel 对象。 - 输出:直接返回 ORM 对象,FastAPI 会自动过滤掉敏感字段(如密码)并序列化为 JSON。
- 无缝支持异步(Async/Await):SQLAlchemy (v1.4+) 和 SQLModel 完美支持异步上下文(配合
asyncpg驱动),与 FastAPI 的异步架构完美契合,不会阻塞事件循环。 - 数据库迁移工具(Alembic):可以通过 Python 代码(Models)自动生成数据库表结构迁移脚本(Schema Migrations),版本控制极其简单。
- 防御 SQL 注入:ORM 在底层自动使用参数化查询,从源头上消除了大部分 SQL 注入的风险。
缺点:
- 性能损耗:由于存在 SQL 生成、结果集对象映射(Object Mapping)、Pydantic 校验等多层包装,在高并发、大吞吐场景下,CPU 和内存开销显著高于
psycopg2。 - N+1 查询陷阱:如果不熟悉 ORM 的“延迟加载(Lazy Loading)”机制,很容易写出在循环中查表的代码,产生大量无谓的数据库连接请求,导致系统骤慢。
- 学习曲线陡峭:SQLAlchemy 是一个功能极其庞大、复杂的库。在处理复杂联表、事务隔离级别、连接池调优时,学习和排坑的成本很高。
三、 核心维度对比表格
对比维度psycopg2 (原生 SQL)FastAPI + SQLAlchemy / SQLModel查询性能🥇极快(无中间开销)🥈较慢(受 ORM 映射和校验损耗影响)开发速度❌慢(写大量样板 SQL 和数据转换代码)🥇极快(自动 CRUD,自动转换 DTO)异步支持❌原生不支持(需用线程池或换 asyncpg)🥇原生支持(配合 asyncpg 完美异步)类型提示 / 补全❌无(SQL 只是字符串)🥇完美(IDE 可精准推断模型属性)维护成本❌高(改一个字段名要搜索全局 SQL 字符串)🥇低(修改 Model 即可,支持 IDE 重构)防 SQL 注入⚠️需手动参数化(稍有不慎容易写出漏洞)🥇天然防范(框架底层强制参数化)
四、 工程实践建议:怎么选?
在实际的企业级 FastAPI 开发中,我们很少走两个极端,通常会采用混合架构(Hybrid Approach):
- 80% 的业务(标准 CRUD / 业务逻辑):使用FastAPI + SQLModel / SQLAlchemy。- 享受自动校验、快速开发、类型补全和 Alembic 自动迁移的好处。
- 20% 的业务(高性能 / 报表 / 复杂联表):在 ORM 的 Session 中执行原生 SQL。- SQLAlchemy 允许你直接通过
session\.execute\(text\("SELECT \.\.\."\)\)执行原生 SQL,这样既保留了 ORM 的连接池管理,又获得了原生 SQL 的极致性能和灵活性。 - 注:如果只用原生 SQL,在 FastAPI 中建议使用asyncpg代替同步的psycopg2。
相似文章
@FinanceYF5: jason:全新的实时翻译模型,目前可以通过api试用。
Jason发布了全新的实时翻译模型,目前可通过API进行试用。
@Michaelzsguo: https://x.com/Michaelzsguo/status/2053217839729791221
本文是一份本地大模型部署指南,涵盖硬件选择、内存计算、Runtime 工具对比及模型量化选择,帮助用户从入门到优化本地推理体验。
@QingQ77: 将阿里达摩院的 ZipEnhancer 降噪模型从 ModelScope pipeline 中剥离,封装为高性能 FastAPI 降噪服务。 https://github.com/gyj1201/zipEnhancer… 阿里达摩院的 Z…
本项目将阿里达摩院的ZipEnhancer降噪模型从ModelScope pipeline剥离,用纯PyTorch重写推理逻辑并封装为FastAPI服务,支持FP16半精度和长音频分段处理,提供多种降噪模型切换和API接口。
@seclink: 分享 《开发者生态信息差报告(2026-06-05)》,有兴趣的朋友可以阅读。 - 现在有人开始把 openclaw 类项目迁移到 AI 眼镜 和 AI 指环等可穿戴设备了 ... - 机器人与具身智能开源 有很多开源的数据和开源的模型 …
分享了一份开发者生态信息差报告,内容包括将openclaw类项目迁移到AI眼镜和指环等可穿戴设备、机器人与具身智能的开源数据与模型,以及AI API中转站与路由的开源应用。
@beefnoode: https://x.com/beefnoode/status/2062816409030389909
本文基于a16z关于Salesforce无界面产品的分析,探讨AI Agent时代企业软件的护城河从用户界面迁移到底层数据模型、权限体系和工作流逻辑的趋势,并分析了CRM、ATS、ERP等系统的迁移难度差异。