You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI中如何区分客户端省略字段与显式设置字段为None?

解决FastAPI中更新字段时区分「省略字段」与「显式设为None」的问题

首先纠正你代码里的语法错误:UpdateUser的字段定义应该用冒号:声明类型,而非等号,正确基础写法如下:

from typing import Optional
from pydantic import BaseModel, Field
from fastapi import FastAPI

app = FastAPI()

class User(BaseModel):
    name : str
    bio  : Optional[str]

class UpdateUser(BaseModel):
    name: Optional[str] = Field(None)
    bio: Optional[str] = Field(None)

接下来解决核心问题:如何区分客户端是没传某个字段(无需更新)还是显式传了None(需要把该字段设为None)。

核心思路

Pydantic模型实例会自动跟踪哪些字段是客户端显式传递的——不管传递的值是不是None。在Pydantic v1中,这个字段集合存在__fields_set__属性里;v2中则是model_fields_set属性。我们可以利用这个集合生成仅包含需要更新字段的字典,再执行数据库更新操作。

具体实现

@app.put("/users/{pk}", response_model=User)
async def put_user(pk: int, payload: UpdateUser) -> User:
    # 模拟从数据库获取目标用户数据
    db_user = {"name": "张三", "bio": "这是我的简介"}
    
    # 获取客户端显式传递的字段集合
    updated_fields = payload.__fields_set__  # Pydantic v1版本用这个
    # updated_fields = payload.model_fields_set  # Pydantic v2版本用这个
    
    # 生成仅包含需要更新字段的字典
    update_data = {field: getattr(payload, field) for field in updated_fields}
    
    # 执行更新:只修改显式传递的字段(包括值为None的情况)
    db_user.update(update_data)
    
    # 转换为User模型返回(模拟数据库更新后的结果)
    return User(**db_user)

效果验证

  • 客户端仅传name字段:{"name": "李四"},updated_fields为{"name"},仅更新name,bio保留原有值。
  • 客户端传bio: null:{"bio": null},updated_fields为{"bio"},会将bio设为None。
  • 客户端传空对象:updated_fields为空集合,不更新任何字段。

进阶优化:自动生成部分更新模型

如果User模型字段较多,不想手动编写UpdateUser,可以用Pydantic的工具自动生成:

# Pydantic v2 写法
from pydantic import BaseModel, Partial

class User(BaseModel):
    name : str
    bio  : Optional[str]

# 自动生成所有字段均为可选的UpdateUser模型
UpdateUser = Partial[User]

生成的模型和手动定义效果完全一致,同样可以通过model_fields_set跟踪显式传递的字段。

内容的提问来源于stack exchange,提问作者odigity

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 07:22:25