如何在Pydantic中替换默认ValidationError为自定义扩展异常?
让Pydantic自动抛出自定义ValidationError子类
要实现让Pydantic模型实例化时自动抛出自定义的MyValidationError(继承自默认ValidationError并添加自定义属性),无需在每个字段验证器中手动修改,可通过以下步骤实现:
1. 定义自定义异常类
继承Pydantic的ValidationError,添加所需的自定义属性(示例中为error_code):
from pydantic import ValidationError class MyValidationError(ValidationError): def __init__(self, *args, error_code: str = "VALIDATION_FAILED", **kwargs): self.error_code = error_code super().__init__(*args, **kwargs)
2. 创建自定义基类模型
通过包装模型的验证逻辑,捕获默认的ValidationError并转换为自定义异常抛出。以下分别提供Pydantic v2和v1的实现:
Pydantic v2 实现
使用model_validator(mode='wrap')包装验证流程:
from pydantic import BaseModel, model_validator, field_validator class CustomBaseModel(BaseModel): @model_validator(mode='wrap') def validate_and_convert_errors(cls, values, handler): try: # 执行默认验证逻辑 return handler(values) except ValidationError as e: # 转换为自定义异常抛出,保留原错误信息与上下文 raise MyValidationError( e.errors(), model=cls, error_code="MODEL_VALIDATION_ERROR" ) from e # 示例业务模型,继承自定义基类 class User(CustomBaseModel): name: str age: int @field_validator('age') def age_must_be_positive(cls, v): if v <= 0: raise ValueError("年龄必须为正整数") return v
Pydantic v1 实现
使用@classmethod覆盖validate方法:
from pydantic import BaseModel, validator class CustomBaseModel(BaseModel): @classmethod def validate(cls, value): try: return super().validate(value) except ValidationError as e: raise MyValidationError( e.raw_errors, model=cls, error_code="MODEL_VALIDATION_ERROR" ) from e class User(CustomBaseModel): name: str age: int @validator('age') def age_must_be_positive(cls, v): if v <= 0: raise ValueError("年龄必须为正整数") return v
3. 测试效果
运行以下测试代码:
try: User(name="Alice", age=-5) except MyValidationError as e: print(f"自定义错误码: {e.error_code}") print(f"错误详情: {e.errors()}")
预期输出
自定义错误码: MODEL_VALIDATION_ERROR 错误详情: [{'type': 'value_error', 'loc': ('age',), 'msg': '年龄必须为正整数', 'input': -5, 'ctx': {'error': ValueError('年龄必须为正整数')}}]
核心优势
- 无需在每个字段验证器中手动修改抛出逻辑,统一在基类处理,减少重复代码
- 自定义异常完全兼容原
ValidationError的所有方法(如errors()、json()),同时扩展了自定义属性 - 通过异常链(
from e)保留原异常上下文,便于调试排查问题
内容的提问来源于stack exchange,提问作者Daniel Bailo
相关产品推荐
相关产品推荐

