Перейти к содержанию

Pydantic

Pydantic  —  это библиотека, которая обеспечивает проведение валидации данных и управление настройками с помощью аннотаций типов.

Рецепты

Зачем нужно делать кастомную базовую Pydantic модель?

Сейчас некоторые со мной не согласятся, но я часто рекомендую делать базовую pydantic модель и наследовать все модели от неё.

Наличие такой глобальной модели позволяет настраивать поведение всех моделей в приложении. Рассмотрю несколько кейсов, когда это может понадобится.

1) Контроль над входными данными. Например, мы хотим округлять все поля которые называются price до трех знаков после запятой. Сделать это можно так:

class CustomBaseModel(BaseModel):
    @root_validator()
    def round_price(cls, data: dict) -> dict:
        prices = {k: round(v, 3) for k, v in data.items() if k == "price"}
        return {**data, **prices}

Валидаторы дают возможность изменять входящие данные, но это стоит использовать с осторожностью.

Такой подход неявный, и я с этим согласен. Ничего не мешает для таких целей сделать ещё одну базовую модель (PriceRoundBaseModel), наследуясь от нашей базовой СustomBaseModel и использовать её там, где такое поведение необходимо.

1) Кастомый энкодер/декодер json. Пакет json из стандартной библиотеки очень медленный. При необходимости ускорить сервис этот пакет в первую очередь пытаются заменить на что-то побыстрее. Это происходит из-за того, что операций по (дe)сериализации json в приложении может быть много, и смена библиотеки, в этом случае, дает ощутимый прирост к общей скорости.

В pydantic есть 2 опции в конфиге, которые позволяют изменять поведение энкодера и декодера. Выглядит это так:

def orjson_dumps(v, *, default):
    # orjson.dumps возвращает байты, поэтому нам надо их декодить, чтобы соответствовать сигнатуре json.dumps
    return orjson.dumps(v, default=default).decode()

class CustomBaseModel(BaseModel):
    class Config:
        json_loads = orjson.loads
        json_dumps = orjson_dumps