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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 15:43:09