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

升级Pydantic v2后自定义类型无法获取info的field_name与data问题

解决Pydantic v2自定义类型中无法访问field_name和data的问题

在Pydantic v2中,普通自定义验证器默认传递的是简化版上下文,导致无法获取field_name和data。核心解决思路是使用带完整上下文的验证器类型,以下分两种实现方式给出解决方案:

1. 类继承式自定义类型(适配原v1写法)

修改自定义类型的__get_pydantic_core_schema__方法,使用core_schema.with_info_plain_validator_function替代general_plain_validator_function,这样验证函数就能拿到包含field_name、data的完整ValidationInfo对象。

from datetime import date
from pydantic import BaseModel, ValidationInfo
from pydantic_core import core_schema

# 假设这是你已有的日期解析函数
def to_date(field_name: str, value: str, formats: list[str], return_str: bool) -> date:
    for fmt in formats:
        try:
            return date.strptime(value, fmt)
        except ValueError:
            continue
    raise ValueError(f"字段 {field_name} 无法解析为日期,支持格式:{formats}")

class CustomDate(date):
    POTENTIAL_FORMATS = []

    @classmethod
    def validate(cls, field_value, info: ValidationInfo) -> date:
        if isinstance(field_value, date):
            return field_value
        # 现在可以正常访问info.field_name和info.data
        return to_date(info.field_name, field_value, cls.POTENTIAL_FORMATS, return_str=False)

    @classmethod
    def __get_pydantic_core_schema__(cls, source_type, handler) -> core_schema.CoreSchema:
        # 使用带完整上下文的验证器
        return core_schema.with_info_plain_validator_function(cls.validate)

class ExampleModel(BaseModel):
    class MyDate(CustomDate):
        POTENTIAL_FORMATS = ['%Y-%m-%d', '%Y/%m/%d']
    dt: MyDate

# 测试
test_data = {"dt": "2024/05/20"}
model = ExampleModel(**test_data)
print(model.dt)  # 输出: 2024-05-20

2. Annotated工厂函数方式

用FieldValidator替代BeforeValidator,并指定mode='before',这样验证函数会接收完整的ValidationInfo上下文。

from datetime import date
from typing import Annotated
from pydantic import BaseModel, FieldValidator, ValidationInfo

def to_date(field_name: str, value: str, formats: list[str], return_str: bool) -> date:
    for fmt in formats:
        try:
            return date.strptime(value, fmt)
        except ValueError:
            continue
    raise ValueError(f"字段 {field_name} 无法解析为日期,支持格式:{formats}")

def custom_date(potential_formats: list[str]):
    def validate_date(field_value, info: ValidationInfo) -> date:
        if isinstance(field_value, date):
            return field_value
        return to_date(info.field_name, field_value, potential_formats, return_str=False)
    # 使用FieldValidator并指定前置验证模式
    return Annotated[date, FieldValidator(validate_date, mode='before')]

class ExampleModel(BaseModel):
    dt2: custom_date(['%Y-%m-%d', '%Y/%m/%d'])

# 测试
test_data = {"dt2": "2024-05-20"}
model = ExampleModel(**test_data)
print(model.dt2)  # 输出: 2024-05-20

关键注意点

  • 类自定义类型必须用with_info_plain_validator_function,不能用general_plain_validator_function,后者只传递简化上下文。
  • Annotated方式必须用FieldValidator+mode='before',普通BeforeValidator不会传递完整的字段信息。
  • 验证函数的第二个参数建议标注为ValidationInfo类型,方便类型检查和IDE提示。

内容的提问来源于stack exchange,提问作者hamdog

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 22:24:51