Fastapi之model_validator
参考:【Python】Pydantic validator 与Fastapi 中validator使用功能介绍
1、model_validator
@model_validator
是 Pydantic 2.x 版本中引入的一个装饰器,用于替换 @root_validator
。它允许在整个模型级别上执行验证逻辑,而不是仅在单个字段上。@model_validator
可以在字段验证之前或之后运行,具体取决于 mode
参数的设置。
主要特点
-
模型级别的验证:
- 允许在整个模型的所有字段都经过初步验证后,再进行进一步的验证逻辑。
-
灵活性:
- 可以在字段验证之前或之后运行,具体取决于
mode
参数的设置。
- 可以在字段验证之前或之后运行,具体取决于
-
替代
@root_validator
:@root_validator
在 Pydantic 2.x 中已被弃用,建议使用@model_validator
。
使用方法
@model_validator
装饰器接受一个 mode
参数,可以是 'before'
或 'after'
:
mode='before'
:在字段验证之前运行。mode='after'
:在字段验证之后运行。
下面详细解释 mode='before'
和 mode='after'
的区别及其影响。
from pydantic import BaseModel, model_validator, Fieldclass User(BaseModel):username: str = Field(..., title='姓名', description='姓名字段需要长度大于6且小于等于12', max_length=12, min_length=6, example="Foo")age: int = Field(..., title='年龄', description='年龄需要大于18岁', ge=18, example=12)password_old: str = Field(..., title='旧密码', description='密码需要长度大于6', min_length=6, example="password123")password_new: str = Field(..., title='新密码', description='密码需要长度大于6', min_length=6, example="newpassword123")@model_validator(mode='before')def check_passwords(cls, values):password_old, password_new = values.get('password_old'), values.get('password_new')if password_old and password_new and password_old == password_new:raise ValueError('新旧密码不能相同')return values# 测试
try:user = User(username="Alice", age=25, password_old="pass", password_new="pass")
except ValueError as e:print(f"发生错误: {e}")
发生错误: 1 validation error for User
Value error, 新旧密码不能相同 [type=value_error, input_value={'username': 'Alice', 'ag... 'password_new': 'pass'}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.5/v/value_error
from pydantic import BaseModel, model_validator, Fieldclass User(BaseModel):username: str = Field(..., title='姓名', description='姓名字段需要长度大于6且小于等于12', max_length=12, min_length=6, example="Foo")age: int = Field(..., title='年龄', description='年龄需要大于18岁', ge=18, example=12)password_old: str = Field(..., title='旧密码', description='密码需要长度大于6', min_length=6, example="password123")password_new: str = Field(..., title='新密码', description='密码需要长度大于6', min_length=6, example="newpassword123")@model_validator(mode='after')def check_passwords(cls, values):password_old, password_new = values.get('password_old'), values.get('password_new')if password_old and password_new and password_old == password_new:raise ValueError('新旧密码不能相同')return values# 测试
try:user = User(username="Alice", age=25, password_old="pass", password_new="pass")
except ValueError as e:print(f"发生错误: {e}")
发生错误: 3 validation errors for User
usernameString should have at least 6 characters [type=string_too_short, input_value='Alice', input_type=str]For further information visit https://errors.pydantic.dev/2.5/v/string_too_short
password_oldString should have at least 6 characters [type=string_too_short, input_value='pass', input_type=str]For further information visit https://errors.pydantic.dev/2.5/v/string_too_short
password_newString should have at least 6 characters [type=string_too_short, input_value='pass', input_type=str]For further information visit https://errors.pydantic.dev/2.5/v/string_too_short
2、ValidationError
ValidationError
是 Pydantic 库中用于表示数据验证错误的一种异常。当 Pydantic 模型在验证传入的数据时,如果数据不符合模型定义的约束条件,就会抛出 ValidationError
。这个异常包含了详细的错误信息,可以帮助开发者和客户端理解哪些字段验证失败以及失败的原因。
主要特点
-
详细的错误信息:
ValidationError
包含一个errors()
方法,该方法返回一个包含所有验证错误的列表。- 每个错误信息通常包括以下部分:
loc
:错误发生的字段路径。msg
:错误的描述信息。type
:错误的类型。
-
自定义异常处理:
- 可以通过自定义异常处理函数来捕获
ValidationError
,并返回更友好的错误响应。
- 可以通过自定义异常处理函数来捕获
from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel, Field, model_validator,ValidationError
from fastapi.responses import JSONResponseapp = FastAPI()class User(BaseModel):username: str = Field(..., title='姓名', description='姓名字段需要长度大于6且小于等于12', max_length=12, min_length=6, example="Foo")age: int = Field(..., title='年龄', description='年龄需要大于18岁', ge=18, example=12)password_old: str = Field(..., title='旧密码', description='密码需要长度大于6', min_length=6, example="password123")password_new: str = Field(..., title='新密码', description='密码需要长度大于6', min_length=6, example="newpassword123")@model_validator(mode='after')def check_passwords(cls, values):password_old, password_new = values.password_old, values.password_newif password_old and password_new and password_old == password_new:raise ValueError('新旧密码不能相同')return values@app.exception_handler(ValidationError)
async def validation_exception_handler(request: Request, exc: ValidationError):return JSONResponse(status_code=422,content={"detail": exc.errors()},)@app.post("/user")
def create_user(user: User):return {'username': user.username,'password_old': user.password_old,'password_new': user.password_new,}if __name__ == "__main__":import uvicornuvicorn.run("main3:app", host="0.0.0.0", port=8002, reload=True)