Python pydantic. Валидация данных
Изучая FastAPI я познакомился с замечательной библиотекой Pydantic. В документации FastAPI отмечается, что "FastAPI стоит на плечах гигантов Starlette(асинхронный веб-фреймворк , который занимается работой с web) и Pydantic(который служит для валидации данных).
В статье "Введение FastAPI" я на реальном примере описал использование Pydantic в связке с SQLAlchemy. А в данной статье мне хочется разобраться с самой библиотекой Pydantic, который используется во многих проектах по всему миру
Что такое Pydantic?
Pydantic - это библиотека , которая обеспечивает проверку данных и управление настройками с использованием аннотаций типов(type annotations)
Установим pydantic
pip install pydantic
Модели
Основным средством определения объектов в pydantic являются модели (модели — это просто классы, которые наследуются от BaseModel).
Создадим первую pydantic модель для поста(Post). Для этого нам нужно будет отнаследоваться от BaseModel. Передадим этой модели сырые данные и посмотрим , что получится. Ниже в примерах код будет работать на Python версии 3.10 и выше.
from datetime import datetime
from pydantic import BaseModel
class Post(BaseModel):
id: int
title: str
text: str
is_published: bool
tags: list[str] = []
published_at: datetime | None = None
if __name__ == '__main__':
input_data = {
'id': '1',
'title': 'Python decorators',
'text': 'Python decorators text',
'is_published': True,
'published_at': '2019-06-01 12:22',
'tags': ['python', 'js', 3],
'another_field': 'Test data',
}
post = Post(**input_data)
print(post.id, type(post.id))
#> 1
print(post.published_at, repr(post.published_at))
#> 2019-06-01 12:22:00 datetime.datetime(2019, 6, 1, 12, 22)
print("Выводим словарь", post.dict())
#> Выводим словарь {'id': 1, 'title': 'Pyton decorators', 'text': 'Python decorators text',
# 'is_published': True, 'tags': ['python', 'js', '3'], 'published_at': datetime.datetime(2019, 6, 1, 12, 22)}
print("Выводим данные в json", post.json())
#> Выводим данные в json {"id": 1, "title": "Python decorators", "text": "Python decorators text",
# "is_published": true, "tags": ["python", "js", "3"], "published_at": "2019-06-01T12:22:00"}
Разберем , что происходит при запуске данного скрипта
- id - имеет целочисленный тип(int) и это поле является обязательным. Как видно выше значение в id мы передали строковое значение , но pydantic его преобразовал его целочисленный. Строки(str), байты(bytes) и числа плавающей запятой pydantic по возможности преобразует в целочисленный. В противном случае возбуждается исключение. Покажем это на примере ниже
from pydantic import BaseModel
class Example(BaseModel):
id: int
if __name__ == '__main__':
print(Example(id='1')) # строковое значние будет преобразовано в 1
#> id=1
print(Example(id=1.123)) # float преобразуется в 1 (отсекается дробовая часть)
#> id=1
# Возникнет исключение валидации ,потому что строковое значние невозможно преобразовать в целочисленный
print(Example(id='this is str'))
#> pydantic.error_wrappers.ValidationError: 1 validation error for Example
# id
# value is not a valid integer (type=type_error.integer)
name - поле имеет строковый тип и является обязательным.
text - поле имеет строковый тип и является обязательным.
is_published - поле имеет булев тип и по умолчанию имеет значение True(Истинно)
published_at - это поле даты и времени, которое не требуется (и принимает значение None, если оно не указано). pydantic будет обрабатывать либо временную метку unix int (например, 1496498400), либо строку, представляющую дату и время.
tags - требует список строковых значений. По возможности входящие значения pydantic будет преобразоывать в строковые значения
Мы создаем объект модели Post и передаем данные. Так как данные валидные , то создается новый объект и при этом как указали выше , некоторые входные данные преобразуются в тот тип , который указан в аннотациях полей.Как видим выше во входных данных(input_data) у нас есть поле another_field, но такого поля нет в модели и поэтому значение этого поля игнорируется
Если входные данные будут неправильными с точки зрения описания модели , то будет вызываться ошибка валидации. Эти исключения мы можем обрабатывать следующим образом:
from pydantic import ValidationError
try:
post = Post(**input_data)
except ValidationError as e:
print(e.json())
Далее мы используем два метода , которые выводят данные в виде словаря(метод BaseModel.dict()) и виде json (метод BaseModel.json()). Есть еще другие методы и атрибуты модели , которые мы рассмотрим ниже
Методы модели BaseModel
dict() - Возвращает словарь поля и значения модели
json() - Возвращает строковое представление JSON метода dict()
copy() - Возвращает копию модели(по умолчанию поверхностное копирование)
parse_obj()- метод для загрузки любого объекта в модель с обработкой ошибок, если объект не является словарем
parse_raw() - метод для загрузки строк различных форматов
parse_file() - похож на parse_raw() но для путей к файлам;
from_orm() - загружает данные в модель из произвольного класса; (режим ORM)
schema() - возвращает словарь, представляющий модель в виде схемы JSON.
schema_json() - Возвращает строковое представление JSON метода schema()
construct() - метод класса для создания моделей без запуска проверки
Заключение
В этой статье мы показали как создавать модели , как объявлять поля с типами аннотаций, показали как pydantic пытается преобразовать входные данные и расписали методы и аттрибуты моделей. А так библиотека pydantic имеет еще много классных возможностей , о которых я расскажу в следующей статье