我正在尝试创建一个接受特定格式的字符串日期时间的模型,但如果字符串值是空字符串“”,则它应该在模型中作为 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)
我也很困惑为什么这不起作用。原因是
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)