🧩 ORM 技术选型指南:SQLAlchemy vs SQLModel

面向 Python 开发者(尤其是 FastAPI / 数据 / 爬虫工程师)的现代数据库操作实践


🔍 一、什么是 ORM?

ORM(Object-Relational Mapping,对象关系映射)是一种编程技术,它将数据库中的 表(table) 映射为编程语言中的 类(class),把 行(row) 映射为 对象(instance),把 列(column) 映射为 属性(attribute)

它允许开发者用面向对象的方式操作数据库,而无需手动拼接 SQL 语句。

🌰 举例说明

# 定义一个用户模型(类 ↔ 表)
class User:
    id = 1
    name = "Alice"

# 创建一个用户对象(对象 ↔ 数据库中的一行)
user = User(name="Alice")

# 保存到数据库(无需写 INSERT)
session.add(user)
session.commit()

优势:代码更直观、可维护性强、减少 SQL 注入风险
劣势:复杂查询可能不如原生 SQL 灵活


🧱 二、SQLAlchemy:Python ORM 的“老大哥”

SQLAlchemy 是 Python 中最强大、最成熟的 ORM 框架之一,诞生于 2006 年,广泛应用于 Flask、Django(可选)、Pyramid 等项目中。

✅ 核心特点

  • 功能极其丰富,支持复杂查询、事务、连接池等
  • 底层控制力强,适合企业级应用
  • 社区庞大,文档完善
  • 但语法相对繁琐,学习曲线较陡

🚀 三、SQLModel:为 FastAPI 而生的现代 ORM

FastAPI 作者 Tiangolo 推出的 SQLModel,是 SQLAlchemyPydantic 的“完美结合体”。

它基于:

  • SQLAlchemy:提供强大的数据库操作能力
  • Pydantic:提供数据验证、类型提示、API 序列化

✅ 核心优势

特性 说明
单一模型,双重用途 一个类同时用于数据库操作和 API 输入/输出,无需 models.py + schemas.py
强类型提示 完美支持 mypy、IDE 自动补全、类型检查
零额外代码生成 OpenAPI 文档 可直接作为 FastAPI 的 response_model,自动集成 Swagger UI
简洁现代的语法 使用 Python 类型注解定义字段,代码更直观

🆚 四、SQLAlchemy vs SQLModel:对比一览

对比项 SQLAlchemy SQLModel
定义方式 Column(Integer) id: int = Field(...)
类型提示 弱(需注解辅助) 强(原生 Pydantic 支持)
FastAPI 响应支持 ❌ 需转为 dict 或使用 from_attributes=True ✅ 可直接作为 response_model
是否需要额外 schema ✅ 通常需要 schemas.py ❌ 不需要,模型即 schema
主键定义 Column(Integer, primary_key=True) Field(primary_key=True)
默认值 default=... in Column Field(default=...)default_factory=...
学习成本 高(功能多,概念复杂) 中(更直观,适合现代 Python 开发者)
适用场景 复杂企业级应用、高定制化 ORM 快速开发、API 服务、中小型项目、数据管道

🛠️ 五、最佳实践建议:以 SQLModel 为主,按需使用 SQLAlchemy

“用 SQLModel 写 90% 的代码,用 SQLAlchemy 写 10% 的高性能/复杂查询”

✅ 推荐策略

场景 推荐工具
日常增删改查(CRUD) ✅ SQLModel ORM
FastAPI 请求/响应模型 ✅ SQLModel(直接作为 response_model
爬虫数据入库(小批量) ✅ SQLModel session.add()
大批量数据插入(10万+) ⚠️session.bulk_insert_mappings()(原生 SQLAlchemy)
复杂查询(子查询、窗口函数) ⚠️select(...), text("...")(原生 SQLAlchemy)
聚合分析(GROUP BY, AVG) ✅ 混合使用:select(func.avg(...))

💡 六、关键认知:SQLModel 与 SQLAlchemy 是“一体两面”

SQLModel 并不是替代 SQLAlchemy,而是它的“现代化封装”

🔗 它们的关系是:

SQLModel = SQLAlchemy ORM + Pydantic + 更好的默认配置

因此:

  • ✅ 您定义的 class User(SQLModel, table=True) 本质上就是一个 SQLAlchemy ORM 类
  • Session 就是 SQLAlchemy 的 Session
  • engine 就是 SQLAlchemy 的 Engine
  • ✅ 您可以无缝混用两种风格,无需重新连接或重复定义模型

🧪 七、实战代码:混合使用 SQLModel 与 SQLAlchemy

# main.py
from sqlmodel import SQLModel, Field, create_engine, Session
from sqlalchemy import select, text, func

# 1. 定义模型(SQLModel 方式)
class User(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    email: str
    age: int

# 2. 创建引擎和会话
engine = create_engine("sqlite:///example.db")
SQLModel.metadata.create_all(engine)

# 3. 使用同一个 Session,自由切换风格
with Session(engine) as session:
    # ✅ 场景1:普通插入(SQLModel 风格)
    user = User(name="Alice", email="a@b.com", age=25)
    session.add(user)
    session.commit()

    # ✅ 场景2:大批量插入(SQLAlchemy 原生方法)
    bulk_data = [
        {"name": "Bob", "email": "b@b.com", "age": 30},
        {"name": "Charlie", "email": "c@c.com", "age": 35},
    ]
    session.bulk_insert_mappings(User, bulk_data)
    session.commit()

    # ✅ 场景3:复杂查询(SQLAlchemy select)
    users = session.exec(
        select(User).where(User.age > 20)
    ).all()

    # ✅ 场景4:原生 SQL 查询
    result = session.exec(
        text("SELECT name, COUNT(*) as cnt FROM user GROUP BY name")
    ).all()

    # ✅ 场景5:聚合查询
    avg_age = session.exec(
        select(func.avg(User.age))
    ).one()

    print(f"平均年龄: {avg_age}")

所有操作基于同一个连接、同一个会话、同一个模型无缝切换,零成本集成


🎯 八、给数据/爬虫工程师的终极建议

如果您是:

  • ✅ 数据开发工程师
  • ✅ 爬虫工程师
  • ✅ FastAPI 开发者
  • ✅ 脚本/项目并重

强烈推荐将 SQLModel 作为首选数据库工具

因为它能:

  • 🚀 提升开发效率:减少重复模型定义
  • 🧪 增强代码安全:类型提示 + 数据验证
  • 📦 统一数据流:爬虫 → 存库 → API 暴露,一个模型贯穿始终
  • 保留高性能选项:需要时直接调用 SQLAlchemy 原生方法

📌 总结

工具 定位 推荐使用场景
SQLAlchemy 功能全面的“底层引擎” 复杂 ORM 操作、企业级系统
SQLModel 现代化的“开发加速器” FastAPI、数据管道、爬虫、快速开发

🔑 最佳策略
以 SQLModel 为主力,享受开发效率;
在性能瓶颈处,无缝切入 SQLAlchemy 原生 API。