文章目录
前言
为了规范模型的创建与使用,减少不必要的代码冗余,维护数据的安全性,进行模型设计时,设置基本模型,输入模型,输出模型以及数据库操作模型;
基本模型中包含了基础字段,避免模型定义重复;
输入模型用于用户输入字段时进行字段的校验;
输出模型用于返回给用户特定信息,避免泄露敏感信息;
数据库操作模型用于进行模型的数据库操作;
以下是详细解释
输入验证 vs 输出序列化
- 输入验证模型 (UserCreate):验证客户端传入的数据
- 输出序列化模型 (UserResponse):控制返回给客户端的数据格式
1.分层模型设计
from pydantic import BaseModel
# 基础模型 (共享字段)
class UserBase(BaseModel):
username: str
# 输入验证模型 (扩展基础模型)
class UserCreate(UserBase):
# 添加创建用户特有的验证规则
password: str # 密码只在创建时需要
email: str # 邮箱验证等
class Config:
extra = "forbid" # 禁止额外字段
# 输出序列化模型 (扩展基础模型)
class UserResponse(UserBase):
id: str
created_at: datetime
class Config:
orm_mode = True # 允许从ORM对象转换
# 数据库模型 (SQLAlchemy)
class User(Base):
__tablename__ = "users"
id = Column(String, primary_key=True)
username = Column(String)
password = Column(String) # 实际存储哈希值
created_at = Column(DateTime)
2.路由中使用分层模型
@router.post("/users")
def create_user(
user_data: UserCreate, # 输入验证
db: Session = Depends(get_db)
):
try:
# 1. 输入验证由UserCreate自动完成
# 2. 创建数据库对象
db_user = User(
id=get_uuid(),
username=user_data.username,# 传入校验的字段名
password=hash_password(user_data.password), # 安全处理
created_at=datetime.utcnow()
)
db.add(db_user)
db.commit()
db.refresh(db_user) # 获取数据库生成的值
# 3. 使用输出模型序列化
return UserResponse.from_orm(db_user)
except Exception as e:
db.rollback()
return error_response(500, str(e))
3.关键优化点
-
字段复用:
UserBase
包含共享字段(如username
)- 输入和输出模型继承基础模型,避免重复定义
-
关注点分离:
UserCreate
:专注输入验证(密码强度、邮箱格式等)UserResponse
:专注输出控制(排除敏感字段如密码)
-
自动序列化:
# 使用Pydantic的orm_mode return UserResponse.from_orm(db_user) # 自动将SQLAlchemy对象转换为响应字典
-
安全控制:
- 输入模型包含密码字段(验证后立即哈希处理)
- 输出模型完全排除密码字段
4.响应处理优化
修改您的 success_response
函数以更好地支持 Pydantic 模型:
def success_response(
code: int = 0,
message: str = "操作成功",
data: Union[BaseModel, dict, list] = None
):
# 如果数据是Pydantic模型,自动转换为dict
if isinstance(data, BaseModel):
data = data.dict()
return JSONResponse(
content={"code": code, "message": message, "data": data},
status_code=200
)
5.完整工作流程
6.from_orm()方法详解
UserResponse.from_orm(实例类)
是 Pydantic 提供的一个强大功能,用于将 ORM 对象(如 SQLAlchemy 模型实例)自动转换为 Pydantic 模型实例。
1.核心概念解析
-
from_orm()
方法:- 是 Pydantic 模型的类方法
- 用于从 ORM 对象创建 Pydantic 实例
- 自动提取 ORM 对象中与 Pydantic 模型匹配的属性
-
必需配置:
class UserResponse(BaseModel): # 字段定义... class Config: orm_mode = True # 启用 ORM 模式
2.工作流程
3.实际示例
假设有以下 SQLAlchemy 模型:
class User(Base):
__tablename__ = "users"
id = Column(String, primary_key=True)
username = Column(String) # 校验字段
password = Column(String) # 敏感字段
created_at = Column(DateTime)
is_admin = Column(Boolean)
定义 Pydantic 响应模型:
class UserResponse(BaseModel):
id: str
username: str
created_at: datetime
class Config:
orm_mode = True # 关键配置
使用方式:
@router.post("/users")
def create_user(db: Session = Depends(get_db)):
# 创建数据库用户
db_user = User(
id="user_123",
username="john_doe",
password="secret", # 敏感字段
created_at=datetime.utcnow(),
is_admin=False
)
# 转换为响应模型
return UserResponse.from_orm(db_user)
4.输出结果
{
"id": "user_123",
"username": "john_doe",
"created_at": "2023-07-20T12:34:56.789Z"
}
5.关键特性
-
自动字段映射:
- 只提取 Pydantic 模型中定义的字段
- 忽略 ORM 对象中的其他字段(如
password
,is_admin
)
-
类型转换:
- 自动将数据库类型转换为 Python 类型
- 例如:SQLAlchemy DateTime → Python datetime
-
安全过滤:
- 天然防止敏感数据泄露
- 无需手动排除字段
-
嵌套支持:
class TeamResponse(BaseModel): id: str name: str members: List[UserResponse] # 嵌套模型 class Config: orm_mode = True # 自动处理关系 team = session.query(Team).options(joinedload(Team.members)).first() return TeamResponse.from_orm(team)
6.与直接序列化的区别
方法 | 优点 | 缺点 |
---|---|---|
UserResponse.from_orm(db_user) | 自动过滤敏感字段 类型安全 支持复杂嵌套 | 需要预先定义模型 |
db_user.__dict__ | 简单直接 | 暴露所有字段 包含内部属性 需要手动清理 |
{k: v for k, v in db_user.__dict__ if k[0] != '_'} | 过滤内部属性 | 仍暴露所有数据库字段 无类型控制 |