即使其中一个验证器失败,如何检查所有 Pydantic 验证器,然后在 FastAPI 响应中引发多个 ValueError?

dat*_*ews 7 python python-3.x pydantic fastapi

是否可以调用所有验证器来获取完整的错误列表?

@validator('password', always=True)
def validate_password1(cls, value):
    password = value.get_secret_value()

    min_length = 8
    if len(password) < min_length:
        raise ValueError('Password must be at least 8 characters long.')

    return value

@validator('password', always=True)
def validate_password2(cls, value):
    password = value.get_secret_value()

    if not any(character.islower() for character in password):
        raise ValueError('Password should contain at least one lowercase character.')

    return value
Run Code Online (Sandbox Code Playgroud)

当前的行为似乎一次调用一个验证器。

我的 Pydantic 课程:

class User(BaseModel):
    email: EmailStr
    password: SecretStr
Run Code Online (Sandbox Code Playgroud)

如果我没有在请求中包含email, 或password, 字段,那么我会在数组中得到两个验证失败,这就是我想要对该字段执行的操作password,但当前的行为似乎调用了一个,如果失败则抛出立即出现错误。

Chr*_*ris 6

您不能按照问题中演示的方式针对特定字段引发多个验证错误/异常。下面给出了建议的解决方案。

\n

选项1

\n
更新
\n

请注意,在 Pydantic V2 中,@validator已被弃用并被替换为@field_validator. 请查看此答案以获取更多详细信息和示例。

\n
原答案
\n

使用单个变量连接错误消息,并ValueError在末尾引发一次(如果发生错误):

\n
@validator(\'password\', always=True)\ndef validate_password1(cls, value):\n    password = value.get_secret_value()\n    min_length = 8\n    errors = \'\'\n    if len(password) < min_length:\n        errors += \'Password must be at least 8 characters long. \'\n    if not any(character.islower() for character in password):\n        errors += \'Password should contain at least one lowercase character.\'\n    if errors:\n        raise ValueError(errors)\n        \n    return value\n
Run Code Online (Sandbox Code Playgroud)\n

如果满足上述所有条件语句,则输出将为:

\n
{\n  "detail": [\n    {\n      "loc": [\n        "body",\n        "password"\n      ],\n      "msg": "Password must be at least 8 characters long. Password should contain at least one lowercase character.",\n      "type": "value_error"\n    }\n  ]\n}\n
Run Code Online (Sandbox Code Playgroud)\n

选项2

\n
更新
\n

在 Pydantic V2 中,ErrorWrapper已删除\xe2\x80\x94,请查看迁移指南。如果您想自己实现这一点,请查看 Pydantic V1.9 error_wrappers.py。此外,@validator已被弃用并被@field_validator. 请查看此答案以获取更多详细信息和示例。

\n
原答案
\n

ValidationError使用类列表直接引发ErrorWrapper。

\n
from pydantic import ValidationError\nfrom pydantic.error_wrappers import ErrorWrapper\n\n@validator(\'password\', always=True)\ndef validate_password1(cls, value):\n    password = value.get_secret_value()\n    min_length = 8\n    errors = []\n    if len(password) < min_length:\n        errors.append(ErrorWrapper(ValueError(\'Password must be at least 8 characters long.\'), loc=None))\n    if not any(character.islower() for character in password):\n        errors.append(ErrorWrapper(ValueError(\'Password should contain at least one lowercase character.\'), loc=None))\n    if errors:\n        raise ValidationError(errors, model=User)\n        \n    return value\n
Run Code Online (Sandbox Code Playgroud)\n

由于 FastAPI 似乎是添加loc属性本身,如果使用属性(这是必需的参数)将其添加到 中,loc则最终会出现两次field名称(即 )。因此,您可以将其留空(使用),稍后可以通过验证异常处理程序将其删除,如下所示:passwordErrorWrapperlocNone

\n
from fastapi import Request, status\nfrom fastapi.encoders import jsonable_encoder\nfrom fastapi.exceptions import RequestValidationError\nfrom fastapi.responses import JSONResponse\n\n@app.exception_handler(RequestValidationError)\nasync def validation_exception_handler(request: Request, exc: RequestValidationError):\n    for error in exc.errors(): \n        error[\'loc\'] = [x for x in error[\'loc\'] if x]  # remove null attributes\n        \n    return JSONResponse(content=jsonable_encoder({"detail": exc.errors()}), status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)\n
Run Code Online (Sandbox Code Playgroud)\n

如果满足上述所有条件语句,则输出将为:

\n
{\n  "detail": [\n    {\n      "loc": [\n        "body",\n        "password"\n      ],\n      "msg": "Password must be at least 8 characters long.",\n      "type": "value_error"\n    },\n    {\n      "loc": [\n        "body",\n        "password"\n      ],\n      "msg": "Password should contain at least one lowercase character.",\n      "type": "value_error"\n    }\n  ]\n}\n
Run Code Online (Sandbox Code Playgroud)\n