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

FastAPI使用空Depends()时Pydantic field_validator失效问题

问题原因

当你通过FastAPI的Depends(YourModel)处理包含文件上传的请求时,FastAPI会将模型拆解为表单字段逐个解析。对于Enum类型的字段,FastAPI默认会直接尝试将表单传入的字符串转换为Enum实例——此时如果传入的是Enum的名称(而非定义的value值),转换会直接失败。

而你的自定义field_validator默认是mode="after"(Pydantic v2默认行为),即验证器会在字段完成类型转换后才运行。这就导致类型转换失败时,验证器根本没机会执行,直接返回参数无效的错误。

但直接实例化模型时,Pydantic会完整执行从参数解析到验证的全流程,验证器可以正常拦截并处理Enum名称的转换,所以不会报错。

解决方案

关键是调整验证器的运行时机,让它在类型转换之前执行,提前将传入的Enum名称转换为对应的Enum实例。有两种实现方式:

方式1:修改field_validator的mode参数

给field_validator添加mode="before"参数,确保验证器在字段类型转换前触发:

from fastapi import FastAPI, UploadFile, Depends
from enum import Enum
from pydantic import BaseModel, field_validator

app = FastAPI()

class ItemType(str, Enum):
    IMAGE = "img"
    VIDEO = "vid"

class UploadRequest(BaseModel):
    type: ItemType
    files: list[UploadFile]

    @field_validator("type", mode="before")
    def parse_type_from_name_or_value(cls, value):
        if isinstance(value, str):
            # 优先匹配Enum名称,再匹配Enum值,支持大小写不敏感
            try:
                return ItemType[value.upper()]
            except KeyError:
                return ItemType(value)
        return value

@app.post("/upload")
async def upload_files(request: UploadRequest = Depends()):
    return {
        "type": request.type.value,
        "file_count": len(request.files)
    }

方式2:使用Annotated + BeforeValidator(Pydantic v2推荐)

用Annotated结合BeforeValidator显式声明前置验证逻辑,代码结构更清晰:

from fastapi import FastAPI, UploadFile, Depends
from enum import Enum
from pydantic import BaseModel, BeforeValidator
from typing import Annotated

app = FastAPI()

class ItemType(str, Enum):
    IMAGE = "img"
    VIDEO = "vid"

def parse_item_type(value):
    if isinstance(value, str):
        try:
            return ItemType[value.upper()]
        except KeyError:
            return ItemType(value)
    return value

class UploadRequest(BaseModel):
    type: Annotated[ItemType, BeforeValidator(parse_item_type)]
    files: list[UploadFile]

@app.post("/upload")
async def upload_files(request: UploadRequest = Depends()):
    return {
        "type": request.type.value,
        "file_count": len(request.files)
    }

这两种方式都能让传入的Enum名称(比如"IMAGE")被正确转换为对应的Enum实例,同时兼容原本的Enum值(比如"img")传入,无需依赖自定义的辅助函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 02:37:46