FastAPI更新含可空属性对象的最优方案 兼顾类型校验与灵活更新
解决方案
核心是利用Pydantic内置的字段传入状态跟踪能力,既保留类型校验能力,又能区分「字段未传入」和「主动设为null」两种场景,是FastAPI生态下的标准实现方案。
具体实现步骤
- 改造Pydantic更新模型,所有可更新字段均设为可选,默认值为None
- 调用模型的
model_dump(Pydantic v2)或dict(Pydantic v1)方法时传入exclude_unset=True参数,自动过滤用户未主动传入的字段 - 用过滤后的字段批量更新目标对象即可
示例代码
from fastapi import Body, FastAPI from typing import Optional, Literal import dataclasses from pydantic import BaseModel app = FastAPI() @dataclasses.dataclass class User: name: str type: Optional[Literal['admin', 'guest']] user = User('test_user', 'admin') # 改造后的更新模型:所有字段可选,默认值为None class UpdateUser(BaseModel): name: Optional[str] = None type: Optional[Literal['admin', 'guest']] = None @app.put('/') def put(update_user: UpdateUser): # 只保留用户主动传入的字段,未传入的自动过滤 update_data = update_user.model_dump(exclude_unset=True) # 批量更新,未出现在update_data里的字段不会被修改 for field, value in update_data.items(): setattr(user, field, value) return user
方案优势
- 完全保留Pydantic的类型校验能力:如果传入的字段值不符合类型定义(比如
type传了super_admin),会自动返回422校验错误,不需要手动写校验逻辑 - 完美区分两种场景:如果用户主动传了
{"type": null},type字段会保留在update_data里,会被更新为None;如果用户没传type字段,该字段会被自动过滤,不会修改原有值 - 符合REST API部分更新的标准语义,代码简洁易维护
兼容说明
如果使用Pydantic v1版本,只需将update_user.model_dump(exclude_unset=True)替换为update_user.dict(exclude_unset=True)即可,其余逻辑完全一致。
内容的提问来源于stack exchange,提问作者satodai
相关产品推荐
相关产品推荐

