Модель Pydantic 2.7.0, принимающая строку datetime или None

Я пытаюсь создать модель, которая принимает строку 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)
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
442
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я тоже был в замешательстве, почему это не сработало. Причина в том, что 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)

Большое спасибо. В этом была проблема. Как пожизненный ученик, я также глубоко ценю подробный ответ.

Ray Chan 24.04.2024 20:47

Другие вопросы по теме