如何正确实现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
相关产品推荐
相关产品推荐

