升级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
相关产品推荐
相关产品推荐

