大家好,我是木木。
今天给大家分享一个清晰的 Python 库,sqlmodel。
sqlmodel
SQLModel 来自 FastAPI 作者的生态思路:既然 API 数据模型常用 Pydantic,数据库访问常用 SQLAlchemy,那能不能用一套类型标注同时描述数据校验和数据库表结构?SQLModel 做的就是这件事。它适合 FastAPI、类型标注、Pydantic 和 SQLAlchemy 都已经在团队里出现的场景。
项目地址:https://github.com/fastapi/sqlmodel
官方文档:https://sqlmodel.tiangolo.com/
三大特点
模型统一
一个类既能表达 Pydantic 数据模型,也能映射数据库表,减少重复定义。
类型友好
字段通过 Python 类型标注描述,编辑器提示、校验和团队阅读体验都更清楚。
底层成熟
数据库能力来自 SQLAlchemy,复杂查询仍可借助 SQLAlchemy 的表达能力。
最佳实践
安装方式:python -m pip install sqlmodel==0.0.38
功能一:一个模型同时作为表结构
这段代码解决什么问题:用 SQLModel 定义商品表,字段类型同时服务模型声明和数据库映射,再通过 Session 查询有库存的商品。
importwarningswarnings.filterwarnings("ignore")fromsqlmodelimportField,SQLModel,Session,create_engine,selectengine=create_engine("sqlite:///:memory:")classProduct(SQLModel,table=True):id:int|None=Field(default=None,primary_key=True)name:strprice:intstock:int=0SQLModel.metadata.create_all(engine)withSession(engine)assession:session.add_all([Product(name="Keyboard",price=80,stock=5),Product(name="Mouse",price=30,stock=10),Product(name="Monitor",price=220,stock=0),])session.commit()statement=select(Product).where(Product.stock>0).order_by(Product.price.desc())items=session.exec(statement).all()print("available:",len(items))foriteminitems:print(item.name,item.price,item.stock)
这个例子能看出 SQLModel 的核心吸引力:模型声明非常接近 Pydantic,同时又能创建表和执行查询。
功能二:关系和聚合查询
这段代码解决什么问题:用 Relationship 表达作者和书的关系,再借助 SQLAlchemy 的 func 做分组聚合。SQLModel 不是把 SQLAlchemy 藏起来,而是让你需要时继续使用它。
importwarningswarnings.filterwarnings("ignore")fromsqlalchemyimportfuncfromsqlmodelimportField,Relationship,SQLModel,Session,create_engine,selectengine=create_engine("sqlite:///:memory:")classAuthor(SQLModel,table=True):id:int|None=Field(default=None,primary_key=True)name:strbooks:list["Book"]=Relationship(back_populates="author")classBook(SQLModel,table=True):id:int|None=Field(default=None,primary_key=True)author_id:int=Field(foreign_key="author.id")title:strpages:intauthor:Author=Relationship(back_populates="books")SQLModel.metadata.create_all(engine)withSession(engine)assession:alice=Author(name="Alice")bob=Author(name="Bob")session.add_all([alice,bob])session.commit()session.refresh(alice)session.refresh(bob)session.add_all([Book(author_id=alice.id,title="ORM Notes",pages=180),Book(author_id=alice.id,title="Query Guide",pages=220),Book(author_id=bob.id,title="SQLite Tips",pages=90),])session.commit()statement=(select(Author.name,func.count(Book.id),func.sum(Book.pages)).join(Book).group_by(Author.name).order_by(func.sum(Book.pages).desc()))forname,total,pagesinsession.exec(statement):print(name,total,pages)

如果你已经熟悉 SQLAlchemy,SQLModel 不会让你失去控制。它更像是在模型层加了一层类型和校验友好度。
环境与版本信息
- Demo 环境:Windows 11,Python 3.11
- 关键依赖版本:
SQLAlchemy 2.0.49、pydantic 2.12.5
高级功能
这段代码解决什么问题:通过唯一约束触发提交失败,再回滚 Session。SQLModel 使用 SQLAlchemy Session,因此事务处理仍然要按 SQLAlchemy 的习惯认真做。
importwarningswarnings.filterwarnings("ignore")fromsqlalchemyimportUniqueConstraintfromsqlalchemy.excimportIntegrityErrorfromsqlmodelimportField,SQLModel,Session,create_engine,selectengine=create_engine("sqlite:///:memory:")classAccount(SQLModel,table=True):__table_args__=(UniqueConstraint("name"),)id:int|None=Field(default=None,primary_key=True)name:strbalance:int=0SQLModel.metadata.create_all(engine)withSession(engine)assession:session.add(Account(name="alice",balance=100))session.commit()try:session.add(Account(name="bob",balance=50))session.add(Account(name="alice",balance=200))session.commit()exceptIntegrityErrorasexc:print("rollback:",exc.__class__.__name__)session.rollback()accounts=session.exec(select(Account).order_by(Account.name)).all()print("accounts:",len(accounts))print("names:",", ".join(a.nameforainaccounts))
事务和约束不要因为模型写法更简洁就忽略。SQLModel 能让模型更清楚,但数据库一致性仍然要靠索引、约束、事务和测试共同保证。
适用场景
- 你在写 FastAPI 或类型标注较重的后端项目。
- 你希望 Pydantic 模型和数据库模型减少重复定义。
- 团队愿意继续理解 SQLAlchemy 的 Session、查询和事务边界。
不适用场景
- 你只需要成熟完整的 ORM 能力,且不关心 Pydantic 风格模型。
- 项目已经深度使用 Django ORM,不需要再引入另一套模型体系。
- 团队不熟 SQLAlchemy,却希望 ORM 完全隐藏数据库复杂度。
上线检查
- 区分 API 输入模型和数据库表模型,敏感字段不要直接复用。
- 检查关系查询和聚合 SQL,避免 N+1 或隐式慢查询。
- 对唯一约束、事务回滚和字段校验写测试,别只测 happy path。
总结
SQLModel 的优势是清晰:类型、校验和表结构可以在同一种模型风格里组织起来。它尤其适合 FastAPI + Pydantic + SQLAlchemy 的组合,但仍然需要你理解数据库和 SQLAlchemy 的底层边界。