FastAPI数据库ORM怎么选?我肝了三个Demo后,终于不再纠结了

是不是每次开新项目,到了选ORM这一步,心里的两个小人就开始打架? 一个说:"用 SQLAlchemy吧,生态稳如老狗,万一出问题网上随便一搜就有答案。" 另一个立马反驳:"异步时代了老铁,用 Tortoise-ORM它不香吗?那代码写起来多轻快。" 旁边还有个声音幽幽飘来:"要不试试官方亲儿子 SQLModel?"

别笑,这就是我之前的真实写照。我在 GitHub 上光是看这三个库的对比 issue 就刷了一下午,咖啡喝了三杯,一行代码没写。 最后索性一不做二不休,把这三个家伙挨个拉出来遛遛,写了个简单的用户CRUD,这才算心里有了谱。今天就把这份热乎的经验总结分享给你,主打一个听人劝吃饱饭。


🎯 这三兄弟到底谁是谁?

好,咱们先来盘盘这三位的底细。别嫌啰嗦,搞清楚它们的定位,你心里的秤杆子才能放平。

- SQLAlchemy 2.0:稳重的老大哥

这家伙在 Python 圈子的地位,好比 NBA 里的詹姆斯,资历老、技术全面、粉丝基础庞大。

以前总被人吐槽异步不行,但现在 2.0 版本原生支持 async/await,直接把最后一块短板也给补上了。

缺点就是学习曲线陡了点,配置起来稍微有点啰嗦。

- Tortoise-ORM:轻巧的赛车手

它就是为异步而生的,灵感来自 Django ORM。如果你从 Django 转过来,看这代码简直亲切得想哭。

它跑得快,占用资源少,但生态和社区肯定没老大哥那么广,有时候遇到冷门坑得自己去翻源码。

- SQLModel:官方的亲儿子

它是 FastAPI 作者 tiangolo 搞出来的,最大的杀招就是把 Pydantic 的 Schema 和 SQLAlchemy 的 Model 合二为一了。你再也不用写两份几乎一模一样的类了! 这简直是治愈强迫症的良药。

但它比较新,底层其实跑的还是 SQLAlchemy,可以理解为给老大哥穿了一身更潮的衣服。


🛠️ 别光说不练,上代码看看谁更顺手

咱们看个最简单的"创建用户"功能,直观感受下代码量的差距和手感。

1. SQLAlchemy 2.0 (异步版)

复制代码
# 定义模型 (models.py)
class User(Base):
    __tablename__ = "users"
    id: Mapped[int] = mapped_column(primary_key=True)
    email: Mapped[str] = mapped_column(String(100), unique=True)

# Pydantic 校验 (schemas.py)
class UserCreate(BaseModel):
    email: str

# 路由逻辑 (main.py)
async def create_user(user_data: UserCreate, session: AsyncSession):
    new_user = User(**user_data.model_dump())
    session.add(new_user)
    await session.commit()
    await session.refresh(new_user)
    return new_user

⚠️ 经验之谈:看到没,模型和校验类是分开的。这里千万别学我当初偷懒,直接用同一个类又当校验又当数据库模型, 后面业务一复杂,比如数据库里要存个不对外暴露的字段,那改起来就是牵一发动全身。

2. Tortoise-ORM

复制代码
# 定义模型 (models.py) 
class User(Model):
    id = fields.IntField(pk=True)
    email = fields.CharField(max_length=100, unique=True)

    class Meta:
        table = "users"

# 定义 Pydantic Schema (schemas.py)
class UserCreate(BaseModel):
    email: str

# 路由逻辑 (main.py)
async def create_user(user_data: UserCreate):
    new_user = await User.create(**user_data.model_dump())
    return new_user

是不是清爽多了?直接 User.create() 一把梭。但这也是它容易翻车的地方,因为太像 Django 了,有些人会忘记它底层的异步特性, 在循环里直接 await 搞出一堆慢查询。

3. SQLModel

复制代码
# 定义模型 + Schema 合体 (models.py)
class User(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    email: str = Field(max_length=100, unique=True)

# 路由逻辑 (main.py)
async def create_user(user_data: User, session: AsyncSession):
    session.add(user_data)
    await session.commit()
    await session.refresh(user_data)
    return user_data

你可能会问:"这不就写了一个类吗?那登录时的密码字段怎么处理?" 问得好!SQLModel 的做法是用继承,再写个 UserCreate(User) 把敏感字段过滤掉。虽然文件少了,但对继承逻辑的理解要求高了点,刚上手容易蒙圈。


🤔 最后啰嗦一句,到底怎么选?

其实这个问题的答案,就像买螺丝刀,没有最贵的,只有最合适的。

🔹 如果你是团队开发大型项目:

别犹豫,直接上 SQLAlchemy 2.0。 生态和稳定性压倒一切,你踩过的坑前人早就把路填平了。虽然代码多点,但可控性强。

🔹 如果你是自己搞个小玩具,或者想快速出活:

Tortoise-ORM 会让你爽到飞起。 代码少,逻辑直观,异步性能杠杠的。

🔹 如果你是个强迫症,或者重度 Pydantic 爱好者:

试试 SQLModel 吧,官方亲儿子的名头不是白给的。 统一模型的感觉真的非常治愈。不过要做好当小白鼠的心理准备,毕竟它现在还是 0.x 版本。

说来说去,工具只是手段,能帮你解决问题的就是好工具。这篇文章也只是我个人的一点主观感受,真正哪个适合你,还得自己动手试试才知道。


好啦,今天先唠这么多。如果你觉得这篇用实战肝出来的对比有点用,别藏私,点个赞+关注,或者直接转发给你那个正在纠结 FastAPI 怎么写的同事。

技术路漫漫,咱们搭伴走不孤单。下次再遇到什么奇葩 Bug,咱们接着聊!👋

相关推荐
qq_189807031 小时前
如何通过SSH隧道连接远程数据库_本地端口转发与phpMyAdmin
jvm·数据库·python
InfinteJustice1 小时前
Golang map底层实现原理_Golang map哈希表原理教程【收藏】
jvm·数据库·python
21439651 小时前
如何在MongoDB中监控集群中的僵尸连接_释放长时间不活跃的游标资源
jvm·数据库·python
亚林瓜子1 小时前
AWS Glue Python Shell任务中pip安装依赖库
python·shell·pip·aws·glue·job
qq_206901391 小时前
C#怎么使用全局Using C#global using全局引用怎么配置减少每个文件的using声明【语法】
jvm·数据库·python
好家伙VCC2 小时前
# ARCore+ Kotlin 实战:打造沉浸式增强现实交互应用在
java·python·kotlin·ar·交互
卖报的大地主2 小时前
130万对像素级对齐:SOMA-1M如何打通遥感多模态数据的“最后一公里“
人工智能·python·计算机视觉
亚林瓜子2 小时前
AWS Glue Python Shell任务中读取Athena数据库
数据库·python·shell·aws·glue·athena
zhangchaoxies2 小时前
Golang怎么用K8s Secret管理密钥_Golang如何从K8s Secret安全读取密码和证书【操作】
jvm·数据库·python