Pydantic 1转2:Timestamp/NaT转换验证失败问题求助
解决Pydantic 2中pd.NaT与pd.Timestamp类型校验冲突问题
问题原因
Pydantic 2的类型校验严格度高于Pydantic 1,而pd.NaT的实际类型是NaTType,并非pd.Timestamp的实例。即便你在前置验证器中将字符串'NaT'转换为pd.NaT,字段类型pd.Timestamp的校验依然会失败。
解决方案
方案1:扩展字段类型,兼容NaTType
直接修改字段类型,同时接受pd.Timestamp实例和pd.NaT的类型:
from typing import Union import pydantic from pydantic import BaseModel, ConfigDict import pandas as pd class CheckTimestamp(BaseModel): # 同时兼容pd.Timestamp和pd.NaT的类型 ts: Union[pd.Timestamp, type(pd.NaT)] model_config = ConfigDict(arbitrary_types_allowed=True) @pydantic.field_validator('ts', mode='before') def convert_to_timestamp(value: Union[str, pd.Timestamp]): if value == "NaT": return pd.NaT return pd.Timestamp(value) # 测试通过 sample_model = CheckTimestamp(ts='NaT') print(sample_model.ts) # 输出: NaT
方案2:自定义后置校验逻辑,放行pd.NaT
如果不想修改字段类型,可以在后置验证器中添加逻辑,让Pydantic认可pd.NaT为合法值:
import pydantic from pydantic import BaseModel, ConfigDict import pandas as pd class CheckTimestamp(BaseModel): ts: pd.Timestamp model_config = ConfigDict(arbitrary_types_allowed=True) @pydantic.field_validator('ts', mode='before') def convert_to_timestamp(value): if value == "NaT": return pd.NaT return pd.Timestamp(value) @pydantic.field_validator('ts', mode='after') def allow_nat(value): # 允许pd.NaT通过校验 if pd.isna(value): return value # 非空值仍需是pd.Timestamp实例 assert isinstance(value, pd.Timestamp), "必须是pd.Timestamp实例或pd.NaT" return value # 测试通过 sample_model = CheckTimestamp(ts='NaT') print(sample_model.ts) # 输出: NaT
方案3:封装自定义类型(更优雅)
通过自定义Pydantic类型,统一处理pd.Timestamp和pd.NaT的转换与校验:
import pydantic from pydantic import BaseModel, GetCoreSchemaHandler from pydantic_core import core_schema import pandas as pd class TimestampWithNaT: @classmethod def __get_pydantic_core_schema__(cls, source_type, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: return core_schema.no_info_after_validator_function( cls.validate, core_schema.union_schema([ core_schema.is_instance_schema(pd.Timestamp), core_schema.is_instance_schema(type(pd.NaT)) ]), ) @classmethod def validate(cls, value): if isinstance(value, str): if value == "NaT": return pd.NaT return pd.Timestamp(value) return value class CheckTimestamp(BaseModel): ts: TimestampWithNaT model_config = ConfigDict(arbitrary_types_allowed=True) # 测试通过 sample_model = CheckTimestamp(ts='NaT') print(sample_model.ts) # 输出: NaT
内容的提问来源于stack exchange,提问作者ak_slick
相关产品推荐
相关产品推荐

