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

Pydantic 2.7.0模型:如何将空字符串转为None并验证日期时间

问题原因

你遇到的问题核心在于:Annotated[datetime, BeforeValidator(parse_datetime)] 中的验证器仅作用于 datetime 类型的校验流程。当输入空字符串时,验证器返回 None,但后续Pydantic仍会检查该值是否符合 datetime 类型,因此触发了类型不匹配的错误。而直接传入 None 时,字段的 date_time | None 类型会直接接受 None,不会进入 datetime 的校验流程,所以没有报错。

解决方案

这里提供两种可行的解决方式:

方式一:使用字段级验证器(field_validator)

直接给字段添加前置验证器,覆盖整个字段的校验逻辑,包括处理空字符串转 None、合法日期字符串转 datetime 以及直接接受 None 的场景:

from pydantic import BaseModel, ValidationError, field_validator
from datetime import datetime
from typing import Union

class Model(BaseModel):
    dt: datetime | None

    @field_validator('dt', mode='before')
    def parse_datetime(cls, value):
        # 直接返回None
        if value is None:
            return None
        # 已经是datetime类型,直接返回
        if isinstance(value, datetime):
            return value
        # 空字符串(含全空格)转为None
        if isinstance(value, str) and len(value.strip()) == 0:
            return None
        # 解析合法格式的日期字符串
        try:
            return datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
        except Exception as e:
            raise ValueError(f"日期格式错误,需符合%Y-%m-%d %H:%M:%S:{str(e)}")

# 测试场景
# 空字符串转None
data1 = {"dt": ""}
print(Model.model_validate(data1))  # 输出: dt=None

# 合法日期字符串转datetime
data2 = {"dt": "2024-05-20 12:30:00"}
print(Model.model_validate(data2))  # 输出: dt=datetime.datetime(2024, 5, 20, 12, 30)

# 直接传入None
data3 = {"dt": None}
print(Model.model_validate(data3))  # 输出: dt=None

# 非法格式测试
try:
    Model.model_validate({"dt": "2024-05-20"})
except ValidationError as e:
    print(e)

方式二:调整Annotated类型包含None

将 Union[datetime, None] 纳入Annotated的范围,让验证器处理所有可能的输入类型:

from pydantic import BaseModel, ValidationError, BeforeValidator
from datetime import datetime
from typing import Annotated, Union

def parse_datetime(value: Union[str, datetime, None]):
    if value is None:
        return None
    if isinstance(value, datetime):
        return value
    if len(value.strip()) == 0:
        return None
    try:
        return datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
    except Exception as e:
        raise ValueError(f"日期格式错误,需符合%Y-%m-%d %H:%M:%S:{str(e)}")

# 调整Annotated包含Union类型
date_time = Annotated[Union[datetime, None], BeforeValidator(parse_datetime)]

class Model(BaseModel):
    dt: date_time

# 测试场景
print(Model.model_validate({"dt": ""}))  # dt=None
print(Model.model_validate({"dt": "2024-05-20 12:30:00"}))  # dt=datetime.datetime(2024,5,20,12,30)
print(Model.model_validate({"dt": None}))  # dt=None
说明

两种方式都能实现需求,其中字段级验证器(方式一)更直观,逻辑集中在字段定义处;方式二则适合需要复用该日期解析逻辑到多个字段的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 03:18:10