@validator
、@model_validator
和 @root_validator
这三个装饰器的区别及其适用场景。
1. @validator
- 作用:
@validator
装饰器用于定义针对一个或多个具体字段的验证逻辑。它允许在字段值被设置到模型实例之前或之后执行自定义的验证逻辑。 - 参数:
field_names
:指定要验证的字段名称。pre
:布尔值,指定验证器是在类型验证之前 (pre=True
) 还是在之后 (pre=False
) 运行。always
:布尔值,指定即使该字段没有被提供也运行验证器。
- 适用场景:当需要对某个字段进行特定的检查或转换时,可以使用
@validator
。例如,确保一个字段的值大于零,或者将字符串转换为大写等。
2. @model_validator
- 作用:
@model_validator
装饰器用于定义针对整个模型的验证逻辑。它允许在所有字段的类型验证之后,基于这些字段之间的关系执行更复杂的验证逻辑。 - 参数:
mode
:指定验证器的模式,可以是'before'
、'after'
或'wrap'
。'before'
:在任何字段验证之前运行。'after'
:在所有字段验证之后运行。'wrap'
:包裹现有的验证器。
- 适用场景:当需要根据模型中的多个字段值来决定整体的有效性时,可以使用
@model_validator
。例如,检查两个日期字段之间的时间范围是否合理,或者确保某些字段的组合满足特定条件。
3. @root_validator
- 作用:
@root_validator
装饰器也是用于定义针对整个模型的验证逻辑。它允许在所有字段的类型验证之前或之后,基于这些字段之间的关系执行更复杂的验证逻辑。不过,@root_validator
已经被弃用,建议使用@model_validator
。 - 参数:
pre
:布尔值,指定验证器是在所有字段的类型验证之前 (pre=True
) 还是在之后 (pre=False
) 运行。skip_on_failure
:布尔值,指定如果之前的验证器失败是否跳过当前验证器。
- 适用场景:虽然
@root_validator
仍然可用,但建议使用@model_validator
,因为@model_validator
提供了更多的灵活性和更好的支持。
示例代码
import os
import uvicorn
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, validator, model_validator
from typing import Optional
app = FastAPI()
class UserRegistration(BaseModel):
username: str
password: str
password_confirm: str
age: int
double_age: Optional[int] = None
# 验证年龄
@validator('age')
def validate_age(cls, v):
if v < 18:
raise ValueError('年龄必须大于18岁')
return v
# 验证密码是否匹配
@model_validator(mode='after')
def passwords_match(cls, values):
password = values.password
password_confirm = values.password_confirm
if password != password_confirm:
raise ValueError('密码与确认密码不匹配')
return values
# 设置 double_age
@model_validator(mode='after')
def set_double_age(cls, values):
age = values.age
if age and age >= 18:
values.double_age = age * 2
return values
@app.post("/api/users/register", response_model=UserRegistration)
async def register_user(user: UserRegistration):
# 这里可以添加更多的业务逻辑,例如将用户信息保存到数据库
return user
# 主程序入口
if __name__ == "__main__":
# 获取应用模型名称,用于uvicorn运行
app_model_name = os.path.basename(__file__).replace(".py", "")
print(app_model_name)
# 使用uvicorn运行FastAPI应用
uvicorn.run(f"{app_model_name}:app", host='0.0.0.0', port=1235, reload=True)