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

FastAPI Router用Union参数时无法解析Pydantic Enum类型求助

问题

我定义了三个Pydantic模型,其中DocumentConfigBase包含枚举类型字段mode。在FastAPI路由中为knowledge_config参数使用Union[DocumentConfigCreate, SheetConfigCreate, ImageConfigCreate]类型后,调用API时出现错误:"detail": "'config'",且打印knowledge_config仅输出knowledge_id=1,其余参数丢失。

模型代码

import enum
from typing import Optional, Dict, Any
from pydantic import BaseModel, Field, ConfigDict

class SplitType(str, enum.Enum):
    AUTO = "auto"
    CUSTOM = "custom"


class DocumentConfigBase(BaseModel):
    '''
    document config detail
    '''
    model_config = ConfigDict(use_enum_values=True)
    mode: Optional[SplitType] = Field(
        default=SplitType.AUTO, validate_default=True)
    chunk_size: Optional[str] = "800"
    identifier: Optional[str]
    text_preprocessing_rules: Dict[str, Any]


class DocumentConfigCreate(BaseModel):
    '''
    document config create
    '''
    knowledge_id: int
    config: DocumentConfigBase


class SheetConfigCreate(BaseModel):
    '''
    need to update
    '''
    knowledge_id: int
    pass


class ImageConfigCreate(BaseModel):
    '''
    need to update
    '''
    knowledge_id: int
    pass

路由代码

from fastapi import APIRouter, Body, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import Annotated, Union

router = APIRouter()

@router.post("/config", response_model=KnowledgeConfigModel)
def create_knowledge_config(
    user_id: Annotated[int, Body()], 
    config_type: Annotated[KnowledgeType, Body()], 
    knowledge_config: Union[DocumentConfigCreate, SheetConfigCreate, ImageConfigCreate], 
    session: Session = Depends(get_db)
):
    print('knowledge_config', knowledge_config)

    try:
        knowledge_model = KnowledgeConfigService.create(
            operator=user_id, config_type=config_type,
            knowledge_config=knowledge_config, session=session)
        print('knowledge_model', knowledge_model)
        if knowledge_model is None:
            raise HTTPException(
                status_code=404, detail="Config create failed")
        return knowledge_model
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)) from e

请求参数

{
  "user_id": 0,
  "config_type": "document",
  "knowledge_config": {
    "knowledge_id": 1,
    "config": {
      "mode": "auto",
      "chunk_size": "1000",
      "identifier": "string",
      "text_preprocessing_rules": {}
    }
  }
}
已尝试操作
  • 不传递mode参数时,无错误,可获取所有传入参数,mode自动设为"auto"
  • 移除Union类型,仅使用knowledge_config: DocumentConfigCreate时,无错误,可获取所有传入参数,mode自动设为"auto"
原因与解决方案

问题原因

FastAPI解析Union类型时会按顺序匹配模型,SheetConfigCreate和ImageConfigCreate仅包含knowledge_id字段,FastAPI发现请求数据中存在knowledge_id后,直接匹配了第一个符合的简单模型,忽略了后续的DocumentConfigCreate,导致config字段被丢弃,引发验证错误。

解决方案

方案1:使用Pydantic鉴别器(推荐)

给Union中的模型添加统一鉴别字段,让FastAPI明确匹配对应模型:

from typing import Literal
from pydantic import Discriminator, Annotated

class DocumentConfigCreate(BaseModel):
    knowledge_id: int
    config: DocumentConfigBase
    type: Literal["document"] = "document"

class SheetConfigCreate(BaseModel):
    knowledge_id: int
    type: Literal["sheet"] = "sheet"

class ImageConfigCreate(BaseModel):
    knowledge_id: int
    type: Literal["image"] = "image"

# 路由中修改参数定义
knowledge_config: Annotated[
    Union[DocumentConfigCreate, SheetConfigCreate, ImageConfigCreate],
    Discriminator("type")
]

请求时需带上type字段:

{
  "user_id": 0,
  "config_type": "document",
  "knowledge_config": {
    "type": "document",
    "knowledge_id": 1,
    "config": {
      "mode": "auto",
      "chunk_size": "1000",
      "identifier": "string",
      "text_preprocessing_rules": {}
    }
  }
}

方案2:调整Union模型顺序

将最复杂的DocumentConfigCreate放在Union首位,让FastAPI优先匹配:

knowledge_config: Union[DocumentConfigCreate, SheetConfigCreate, ImageConfigCreate]

注:该方法仅适用于模型字段无重叠冲突的场景,可靠性不如鉴别器。

方案3:根据config_type手动解析

利用已传入的config_type参数,在路由内手动选择模型解析请求体:

from fastapi import Request
import json

@router.post("/config", response_model=KnowledgeConfigModel)
async def create_knowledge_config(
    user_id: Annotated[int, Body()], 
    config_type: Annotated[KnowledgeType, Body()], 
    request: Request,
    session: Session = Depends(get_db)
):
    body = await request.json()
    knowledge_config_data = body.get("knowledge_config")
    
    if config_type == "document":
        knowledge_config = DocumentConfigCreate(**knowledge_config_data)
    elif config_type == "sheet":
        knowledge_config = SheetConfigCreate(**knowledge_config_data)
    elif config_type == "image":
        knowledge_config = ImageConfigCreate(**knowledge_config_data)
    else:
        raise HTTPException(status_code=400, detail="Invalid config_type")
        
    print('knowledge_config', knowledge_config)
    # 后续业务逻辑不变

内容的提问来源于stack exchange,提问作者Yu xin Dong

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 21:13:18