我定义了一个自定义 pydantic 类和一个 FastAPI 路由,如下所示:
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
@app.post("/generate_quiz")
def generate_quiz(qcm_params: Annotated[QuestionParameters, Query()], user: str = Depends(verify_credentials)):
"""Génère un QCM basé sur les paramètres fournis.
PARAMS:
-------
- test_type: str
Le type de test souhaité. Par exemple "multiple_choices"
- categories: List[str]
Une liste des catégories de questions souhaitées.
- number_of_questions: int
Le nombre de question à inclure dans le QCM
RETURN:
-------
List[Question]
"""
test_type = qcm_params.test_type
number_of_questions = qcm_params.number_of_questions
categories = qcm_params.categories
....
当我提出此请求时:
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'
我收到以下错误消息:
{
"detail": [
{
"type": "literal_error",
"loc": [
"query",
"number_of_questions"
],
"msg": "Input should be 5, 10 or 15",
"input": "10",
"ctx": {
"expected": "5, 10 or 15"
}
}
]
}
我不明白为什么查询参数
number_of_questions
被视为字符串输入,除了它是一个 int 值(10)之外,我过去如curl请求或FastAPI文档中所示。
有人可以解释一下我出了什么问题吗? 谢谢!
这是一个已知问题。一位用户建议使用注释和 BeforeValidator
此解决方法 在验证之前将传递的字符串转换为整数。在你的情况下,它看起来像这样:
class QuestionParameters(BaseModel):
test_type: Union[Literal["single_choice", "multiple_choices"], None] = None
number_of_questions: Union[Annotated[Literal[5, 10, 15], BeforeValidator(int)], None] = None
categories: Union[List[str], None] = None
这显然有点冗长。如果可以选择 Python 3.10 或更高版本,您可以使用 unions 的更清晰语法(以及 lists 的 3.9+ 语法)来减少一点:
class QuestionParameters(BaseModel):
test_type: Literal["single_choice", "multiple_choices"] | None = None
number_of_questions: Annotated[Literal[5, 10, 15], BeforeValidator(int)] | None = None
categories: list[str] | None = None
这是一个小型测试套件;它应该适用于任一版本。
>>> QuestionParameters(number_of_questions = None) # None
QuestionParameters(test_type=None, number_of_questions=None, categories=None)
>>>
>>> QuestionParameters(number_of_questions = "5") # Acceptable "integer"
QuestionParameters(test_type=None, number_of_questions=5, categories=None)
>>>
>>> QuestionParameters(number_of_questions = "0") # Unacceptable "integer"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/to/packages/pydantic/main.py", line 209, in __init__
validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 1 validation error for QuestionParameters
number_of_questions
Input should be 5, 10 or 15 [type=literal_error, input_value=0, input_type=int]
For further information visit https://errors.pydantic.dev/2.9/v/literal_error
>>>
>>> QuestionParameters(number_of_questions = "Hello World!") # Non-numeric string
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/to/packages/pydantic/main.py", line 209, in __init__
validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 1 validation error for QuestionParameters
number_of_questions
Value error, invalid literal for int() with base 10: 'Hello World!' [type=value_error, input_value='Hello World!', input_type=str]
For further information visit https://errors.pydantic.dev/2.9/v/value_error
>>>
>>> QuestionParameters(number_of_questions = "5.0") # "Float"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/path/to/packages/pydantic/main.py", line 209, in __init__
validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 1 validation error for QuestionParameters
number_of_questions
Value error, invalid literal for int() with base 10: '5.0' [type=value_error, input_value='5.0', input_type=str]
For further information visit https://errors.pydantic.dev/2.9/v/v