You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 11:18:14