如何自定义Pydantic的友好型验证错误提示信息?
优化Pydantic自定义验证错误消息的方案
不用写大量样板验证器,有几个更高效的解决思路:
1. 利用字段约束参数+自定义错误消息
Pydantic的Field或StringConstraints支持直接配置长度、格式等约束,同时通过error_messages自定义错误文本,完全替代手写验证器的重复逻辑。
示例代码:
from pydantic import BaseModel, EmailStr, Field, StringConstraints from typing import Annotated # 复用的密码类型,封装约束和错误消息 PasswordStr = Annotated[ str, StringConstraints( min_length=8, max_length=32, regex=r"^(?=.*[A-Z])(?=.*\d).+$", error_messages={ "min_length": "密码长度不能少于8位", "max_length": "密码长度不能超过32位", "regex": "密码必须包含至少一个大写字母和一个数字" } ) ] class RegisterModel(BaseModel): email: EmailStr = Field(..., error_messages={"value_error": "请输入有效的邮箱地址"}) password: PasswordStr
这样既保留了Pydantic自动验证的便捷性,又自定义了友好的错误消息,还能把PasswordStr类型复用在其他需要密码验证的模型里。
2. 抽离复用自定义验证器
如果有复杂到无法用内置约束覆盖的逻辑,可以把验证逻辑封装成单独的可复用函数,避免每个模型重复写验证器代码。
示例代码:
from pydantic import BaseModel, EmailStr, field_validator, ValidationInfo import re # 抽离通用密码验证逻辑 def validate_password(value: str, info: ValidationInfo) -> str: if not isinstance(value, str): raise ValueError("密码必须是字符串类型") if len(value) < 8: raise ValueError("密码长度不能少于8位") if len(value) > 32: raise ValueError("密码长度不能超过32位") if not re.search(r"[A-Z]", value): raise ValueError("密码必须包含至少一个大写字母") if not re.search(r"[0-9]", value): raise ValueError("密码必须包含至少一个数字") return value class RegisterModel(BaseModel): email: EmailStr password: str @field_validator("password", mode="before") def _validate_password(cls, value, info): return validate_password(value, info) # 其他模型直接复用验证函数 class LoginModel(BaseModel): password: str @field_validator("password", mode="before") def _validate_password(cls, value, info): return validate_password(value, info)
3. 多语言消息适配
如果需要给不同语言的用户返回对应消息,可以用pydantic-i18n库管理多语言文本,无需硬编码多套消息。
步骤示例:
- 安装依赖:
pip install pydantic-i18n - 创建多语言配置文件(比如
locales/zh.json、locales/en.json)// locales/zh.json { "value_error.email": "请输入有效的邮箱地址", "value_error.any_str.min_length": "密码长度不能少于{limit_value}位", "value_error.any_str.max_length": "密码长度不能超过{limit_value}位", "value_error.str.regex": "密码必须包含至少一个大写字母和一个数字" } - 绑定翻译器到模型:
from pydantic_i18n import PydanticI18n, Config from pydantic import BaseModel, EmailStr, StringConstraints from typing import Annotated config = Config(locales_dir="locales") i18n = PydanticI18n(config) PasswordStr = Annotated[ str, StringConstraints(min_length=8, max_length=32, regex=r"^(?=.*[A-Z])(?=.*\d).+$") ] class RegisterModel(BaseModel): email: EmailStr password: PasswordStr class Config: @classmethod def json_schema_extra(cls, schema, model): # 根据用户请求的语言动态切换,这里示例用中文 schema["error_messages"] = i18n.translate("zh")
内容的提问来源于stack exchange,提问作者Clyde
相关产品推荐
相关产品推荐

