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

如何正确实现Pydantic字典键为Enum/Literal以支持Swagger

解决Pydantic字典键Literal类型在Swagger文档中显示<*>的问题

你遇到的问题是因为FastAPI的OpenAPI生成器默认无法正确解析dict[Literal[...]]类型的键,导致Swagger UI只能显示通用的<*>标识,而字段里的Literal类型能正常识别是因为Pydantic对字段的处理逻辑不同。下面是两种可行的解决方法:

方案一:手动为字典字段指定JSON Schema的键定义

通过Annotated结合JsonSchemaExtra,手动给字典字段添加明确的键结构定义,让Swagger能识别出预定义的键:

from fastapi import FastAPI
from pydantic import BaseModel, Field, JsonSchemaExtra
from typing import List, Literal, Annotated

app = FastAPI()

class Result(BaseModel):
    name: str = Field(title="Name")
    description: str = Field(title="Description")
    status: Literal["WARN", "PASS", "FAIL"] = Field(title="Status")

class Response(BaseModel):
    results: Annotated[
        dict[Literal["WARN", "PASS", "FAIL"], List[Result]],
        JsonSchemaExtra(
            {
                "properties": {
                    "WARN": {"type": "array", "items": {"$ref": "#/components/schemas/Result"}},
                    "PASS": {"type": "array", "items": {"$ref": "#/components/schemas/Result"}},
                    "FAIL": {"type": "array", "items": {"$ref": "#/components/schemas/Result"}},
                },
                "additionalProperties": False,  # 禁止额外的键,保证符合预定义规则
            }
        ),
        Field(title="Results")
    ]

@app.get("/test", response_model=Response)
def test():
    res = {'PASS': [{'name': 'name', 'description': 'desc', 'status': 'PASS'}], 
           'WARN': [],
           'FAIL': []
           }
    return Response(results=res)

方案二:改用固定字段的Pydantic模型替代字典

如果可以调整模型结构,直接定义一个包含三个固定字段的模型来替代字典,这种方法更直观,类型检查也更严格:

from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import List, Literal

app = FastAPI()

class Result(BaseModel):
    name: str = Field(title="Name")
    description: str = Field(title="Description")
    status: Literal["WARN", "PASS", "FAIL"] = Field(title="Status")

# 定义包含固定键的模型
class ResultsData(BaseModel):
    WARN: List[Result] = Field(default_factory=list, title="WARN 结果列表")
    PASS: List[Result] = Field(default_factory=list, title="PASS 结果列表")
    FAIL: List[Result] = Field(default_factory=list, title="FAIL 结果列表")

class Response(BaseModel):
    results: ResultsData = Field(title="Results")

@app.get("/test", response_model=Response)
def test():
    res = {'PASS': [{'name': 'name', 'description': 'desc', 'status': 'PASS'}], 
           'WARN': [],
           'FAIL': []
           }
    # 将字典转换为固定字段模型
    return Response(results=ResultsData(**res))

原理说明

原来的dict[Literal["WARN", "PASS", "FAIL"], List[Result]]写法,Pydantic会生成一个匹配这三个字符串的正则规则作为字典键的约束,但Swagger UI不会解析这个正则来展示具体的键,只会显示<*>。而上面两种方法要么手动指定了明确的键结构,要么直接用固定字段模型,都能让Swagger正确展示预定义的键。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 20:05:18