当前位置: 首页 > backend >正文

FastAPI 中,数据库模型(通常使用 SQLAlchemy 定义)和接口模型(使用 Pydantic 定义的 schemas)的差异

在 FastAPI 中,数据库模型(通常使用 SQLAlchemy 定义)和接口模型(使用 Pydantic 定义的 schemas)虽然都用于表示数据结构,但它们有明确的职责区分。以下是它们的核心区别和协作方式:


1. 数据库模型 (Models)

位置:通常在 models.py 中定义
技术:使用 SQLAlchemy ORM
目的:直接映射数据库表结构,处理数据库操作
特点

from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_baseBase = declarative_base()class UserDB(Base):  # 数据库模型__tablename__ = "users"id = Column(Integer, primary_key=True, index=True)username = Column(String(50), unique=True)  # 数据库约束email = Column(String(100))hashed_password = Column(String(200))  # 敏感字段created_at = Column(DateTime)  # 数据库自动生成的时间戳

关键特性

  • 包含数据库特有的字段类型(如 Column
  • 定义表名、主键、索引、约束等
  • 包含敏感字段(如密码哈希)
  • 包含 ORM 关系(如 relationship
  • 可能有数据库自动生成的字段(如创建时间)

2. 接口模型 (Schemas)

位置:通常在 schemas.py 中定义
技术:使用 Pydantic BaseModel
目的:定义 API 输入/输出的数据结构
特点

from pydantic import BaseModel, EmailStrclass UserCreate(BaseModel):  # 创建用户的请求模型username: stremail: EmailStr  # 自动邮箱格式验证password: strclass UserPublic(BaseModel):  # 返回给用户的响应模型id: intusername: stremail: strclass UserPrivate(UserPublic):  # 内部使用的扩展模型hashed_password: str

关键特性

  • 使用 Python 原生类型(str, int 等)
  • 内置数据验证(如 EmailStr
  • 可定义不同场景的模型(创建/响应/更新)
  • 不包含数据库技术细节
  • 可配置响应排除敏感字段

3. 核心区别对比表

特性数据库模型 (Models)接口模型 (Schemas)
职责数据库表映射API 数据验证和序列化
技术SQLAlchemy ORMPydantic
字段类型Column(Integer)Python 原生类型 (int, str)
敏感字段包含密码等敏感信息通常排除敏感字段
关系处理直接定义 relationship通过嵌套模型表示
自动生成字段包含 (如 created_at)通常不包含
数据验证基础约束 (如 unique=True)高级验证 (正则、邮箱格式等)

4. 协作流程示例

用户注册场景:
客户端FastAPI 路由Pydantic 模型数据库模型数据库POST /users (JSON: {username, email, password})用 UserCreate 验证输入验证通过的数据转换 UserCreate → UserDB 模型执行 INSERT 操作返回创建的数据库对象转换 UserDB → UserPublic 模型序列化为 JSON返回 201 Created (UserPublic)客户端FastAPI 路由Pydantic 模型数据库模型数据库
代码实现:
# schemas.py
class UserCreate(BaseModel):username: stremail: EmailStrpassword: strclass UserPublic(BaseModel):id: intusername: stremail: str# models.py
class UserDB(Base):__tablename__ = "users"id = Column(Integer, primary_key=True)username = Column(String(50), unique=True)email = Column(String(100))hashed_password = Column(String(200))# crud.py
def create_user(db: Session, user: schemas.UserCreate):# 转换并处理密码hashed_pw = hash_password(user.password)# 创建数据库模型db_user = models.UserDB(username=user.username,email=user.email,hashed_password=hashed_pw)db.add(db_user)db.commit()return db_user# main.py
@app.post("/users", response_model=schemas.UserPublic)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):db_user = crud.create_user(db, user)return db_user  # 自动转换为 UserPublic

5. 为什么需要分离?

  1. 安全隔离

    • 数据库模型包含敏感字段(如密码哈希)
    • 接口模型可排除敏感字段(通过 response_model
  2. 职责分离

    • 数据库模型关注存储结构
    • 接口模型关注API契约
  3. 灵活性

    # 同一个数据库模型对应多个接口模型
    class UserUpdate(BaseModel):  # 更新专用模型email: Optional[EmailStr]password: Optional[str]
    
  4. 验证与约束解耦

    • 数据库约束:唯一索引、外键关系
    • API验证:邮箱格式、密码强度
  5. 避免技术泄露

    • 接口模型不暴露数据库技术细节(如 SQLAlchemy 类型)
    • 保持 API 的稳定性和可替换性

最佳实践建议

  1. 单向依赖
    Schemas 应该 不依赖 Models,保持解耦

  2. 转换层
    在路由和 CRUD 操作之间进行模型转换:

    # 在路由处理函数中
    db_user = UserDB(**user_create.dict())
    
  3. 使用 orm_mode
    使 Pydantic 能直接处理 ORM 对象:

    class UserPublic(BaseModel):class Config:orm_mode = True  # 允许从ORM对象创建
    
  4. 分层设计

    app/
    ├── models.py    # SQLAlchemy 模型
    ├── schemas.py   # Pydantic 模型
    ├── crud.py      # 数据库操作(使用 models)
    └── api.py       # 路由(使用 schemas 和 crud)
    

这种分离设计使得 FastAPI 应用能够:

  • 安全地处理敏感数据
  • 独立演化数据库和API
  • 提供清晰的API文档(通过Pydantic自动生成)
  • 保持代码的可维护性和可测试性
http://www.xdnf.cn/news/15930.html

相关文章:

  • 【智能协同云图库】智能协同云图库第二期:基于腾讯云 COS 对象存储—开发图片各功能模块
  • SQLite以及Room框架的学习:用SQLite给新闻app加上更完善的登录注册功能
  • 蜂窝物联网模组市场新展望:中国企业继续保持最强竞争力
  • 进阶向:基于Python的电脑硬件监控工具(GUI + 系统信息采集)
  • 51c大模型~合集157
  • 138. Java 泛型 - 通配符捕获Helper程序方法:类型安全解决方案
  • 二维码扫描登录流程详解
  • 【设计模式】迭代器模式 (游标(Cursor)模式)
  • JavaEE初阶第十期:解锁多线程,从 “单车道” 到 “高速公路” 的编程升级(八)
  • WinUI3开发_Frame用法
  • 服务器设置国外IP无法访问对防御攻击有用吗?
  • 一文详解REST风格
  • 一个适合MCU的分级菜单框架
  • .NET SDK 9.0.200引入对SLNX解决方案文件的支持
  • django filter按两个属性 去重
  • Linux——自制shell命令行解释器
  • 【LeetCode 热题 100】208. 实现 Trie (前缀树)
  • 剖析Sully.ai:革新医疗领域的AI助手功能启示
  • ssms(SQL 查询编辑器) 添加快捷键 Ctrl+D(功能等于Ctrl+C + Ctrl+V),一步到位
  • Bun v1.2.19发布,node_modules隔离,sql比node快6倍
  • Kotlin 高阶函数初步学习
  • Laravel 系统版本查看及artisan管理员密码找回方法针对各个版本通用方法及原理-优雅草卓伊凡
  • 信息学奥赛一本通 1576:【例 2】选课 | 洛谷 P2014 [CTSC1997] 选课
  • 子网划分核心原理 (网络原理1)
  • [学习] Hilbert变换:从数学原理到物理意义的深度解析与仿真实验(完整实验代码)
  • 《通信原理》学习笔记——第五章
  • Spring 源码阅读(二) 核心概念解析 ApplicationContext、类型转化
  • 【PyTorch】图像二分类项目
  • 【JS逆向基础】数据库之mysql
  • 7.19-7.20 Java基础 | File类 I/O流学习笔记