Я пытаюсь создать модель, которая принимает строку datetime в определенном формате, но если строковое значение представляет собой пустую строку «», оно должно быть в модели как тип 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
выполняется перед внутренней логикой проверки (см. документацию ). Если бы вы взяли PlainValidator
, который работает вместо внутренней логики проверки (см. документацию), он работает нормально.
Итак, проблема с 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)
Большое спасибо. В этом была проблема. Как пожизненный ученик, я также глубоко ценю подробный ответ.