FastAPI结合Pydantic与Typing Literal时触发literal_error(422 Unprocessable Entity)问题求助
FastAPI结合Pydantic与Typing Literal时触发literal_error(422 Unprocessable Entity)问题求助
我来帮你分析下这个问题的原因,再给出对应的解决方案~
问题原因
你遇到的literal_error本质是类型不匹配:
- 你的Pydantic模型中,
number_of_questions定义为Union[Literal[5, 10, 15], None]——这里的Literal限定的是整数类型的取值(5、10、15都是整数)。 - 但HTTP请求的Query参数默认都是以字符串形式传递的,比如你curl里的
number_of_questions=10,实际会被解析成字符串"10",而不是整数10。 - 字符串
"10"和Literal里的整数10不属于同一类型,所以Pydantic的验证就失败了,触发了这个错误。
解决方案
这里给你三种可行的解决方式,你可以根据自己的代码习惯选择:
方案1:给Pydantic模型字段添加Query注解(推荐)
在Pydantic模型的字段定义中,直接使用Query()来标记字段为Query参数,FastAPI会自动帮你完成字符串到整数的类型转换,同时保留Literal的取值限制:
from fastapi import Query, Depends, Annotated from pydantic import BaseModel, Literal, Union, List from typing import Optional class QuestionParameters(BaseModel): test_type: Union[Literal["single_choice", "multiple_choices"], None] = Query( None, description="Le type de test souhaité. Par exemple 'multiple_choices'" ) number_of_questions: Union[Literal[5, 10, 15], None] = Query( None, description="Le nombre de question à inclure dans le QCM" ) categories: Union[List[str], None] = Query( None, description="Une liste des catégories de questions souhaitées." ) @app.post("/generate_quiz") def generate_quiz( qcm_params: Annotated[QuestionParameters, Query()], user: str = Depends(verify_credentials) ): test_type = qcm_params.test_type number_of_questions = qcm_params.number_of_questions categories = qcm_params.categories # ... 后续业务逻辑
方案2:用Pydantic字段验证器手动处理类型转换
如果不想在模型中引入FastAPI的Query,可以给number_of_questions添加一个字段验证器,提前把输入的字符串转成整数:
from fastapi import Depends, Annotated from pydantic import BaseModel, Literal, Union, List, field_validator from typing import Optional class QuestionParameters(BaseModel): test_type: Union[Literal["single_choice", "multiple_choices"], None] = None number_of_questions: Union[Literal[5, 10, 15], None] = None categories: Union[List[str], None] = None # 字段验证器:在解析前把输入转成整数 @field_validator("number_of_questions", mode="before") def parse_to_int(cls, value): if value is None: return None try: return int(value) except ValueError: raise ValueError("number_of_questions 必须是整数,可选值为5、10、15") @app.post("/generate_quiz") def generate_quiz( qcm_params: Annotated[QuestionParameters, Query()], user: str = Depends(verify_credentials) ): # 你的原有业务逻辑 test_type = qcm_params.test_type number_of_questions = qcm_params.number_of_questions categories = qcm_params.categories # ...
方案3:拆分Query参数(放弃模型绑定)
如果觉得用模型管理Query参数太繁琐,也可以直接把每个参数单独定义为Query参数,FastAPI会自动处理类型转换:
from fastapi import Query, Depends, Annotated from typing import Union, Literal, List @app.post("/generate_quiz") def generate_quiz( test_type: Union[Literal["single_choice", "multiple_choices"], None] = Query( None, description="Le type de test souhaité. Par exemple 'multiple_choices'" ), number_of_questions: Union[Literal[5, 10, 15], None] = Query( None, description="Le nombre de question à inclure dans le QCM" ), categories: Union[List[str], None] = Query( None, description="Une liste des catégories de questions souhaitées." ), user: str = Depends(verify_credentials) ): # 你的原有业务逻辑 # ...
验证测试
修改完成后,你可以再用原来的curl请求测试:
curl -X 'POST' \ 'http://localhost:8000/generate_quiz?test_type=single_choice&number_of_questions=10&categories=Automation&categories=Data%20Science' \ -H 'accept: application/json'
这时候number_of_questions=10会被正确解析成整数10,符合Literal的取值限制,就不会再触发错误了。
备注:内容来源于stack exchange,提问作者Guy NANA
相关产品推荐
相关产品推荐

