Pydantic 2.7.0 模型接受字符串日期时间或无

问题描述 投票:0回答:1

我正在尝试创建一个接受特定格式的字符串日期时间的模型,但如果字符串值是空字符串“”,则它应该在模型中作为 None 类型。

我正在使用 BeforeValidator,我认为这是正确的方法。

在下面的代码中,我希望 parse_datetime 函数返回 None 类型,然后将其传递给 pydantic 验证器。

有人能引导我走向正确的方向吗?

from pydantic import (
    BaseModel,
    Field,
    ValidationError,
    BeforeValidator,
)
from typing import Annotated, Any, Union
from datetime import datetime, date


def parse_datetime(value: str):
    print(len(value.strip()))
    if len(value.strip()) > 0:
        try:
            return datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
        except Exception as e:
            raise ValueError(str(e))
    else:
        print("returning None")
        value = None
        return value


date_time = Annotated[datetime, BeforeValidator(parse_datetime)]


class Model(BaseModel):
    dt: date_time | None

使用空字符串,我收到验证错误

data = {"dt": ""}
try:
    Model.model_validate(data)
except ValidationError as e:
    print(e)
1 validation error for Model
dt
  Input should be a valid datetime [type=datetime_type, input_value=None, input_type=NoneType]

但是传递 None 类型是可行的

data = {"dt": None}

try:
    Model.model_validate(data)
except ValidationError as e:
    print(e)
python python-3.x pydantic-v2
1个回答
0
投票

我也很困惑为什么这不起作用。原因是

BeforeValidator
在内部验证逻辑之前运行(参见 docs)。如果您采用了运行内部验证逻辑的 PlainValidator
(请参阅 
docs),它就可以正常工作。 所以BeforeValidator

的问题在于注释的类型。您只能在数据类型

BeforeValidator

 上调用 
datetime
 (
Annotated[datetime, ...]
)。因此内部验证逻辑仅接受 
datetime
 而不是 
None
如果将注释更改为 
Annotated[datetime | None, BeforeValidator(parse_datetime)]

它将正常工作。

from pydantic import (
    BaseModel,
    BeforeValidator,
)
from typing import Annotated
from datetime import datetime


def parse_datetime(value: str):

    if value.strip():
        try:
            return datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
        except Exception as e:
            raise ValueError(str(e))
    else:
        return None


date_time = Annotated[datetime | None, BeforeValidator(parse_datetime)]


class Model(BaseModel):
    dt: date_time

Model.model_validate({'dt': ' '})
# Model(dt=None)


© www.soinside.com 2019 - 2024. All rights reserved.