Сегодня мы расширим наши знания, научимся создавать и обрабатывать вложенные структуры данных. Ведь в реальных приложениях запросы редко состоят из одного уровня ключ-значение. JSON-объекты с вложенностью — наше все! Ну а если вы мечтали почувствовать себя программистом, "гуляющим по лесу деревьев JSON", — ваша мечта сбывается.
Представьте себе, что вы разрабатываете API для интернет-магазина. Запрос клиенту может содержать массив товаров, каждый из которых имеет свои атрибуты: название, цену, категорию и даже вложенные объекты — например, информацию о поставщике. Эти данные необходимо валидировать не только на верхнем уровне, но и глубже — для каждого товара и связанных объектов. Pydantic позволяет нам справиться с этим элегантно и эффективно.
Что такое вложенные модели?
В Pydantic вложенные модели — это такие модели, которые содержат другие Pydantic-модели в качестве атрибутов. В сущности, это способ построить древовидные структуры данных, где каждый уровень данных валидируется автоматически.
Вот вам аналогия: представьте матрешку. Каждый вложенный уровень проверяется на соответствие определенным правилам, задающим форму данных. В итоге у вас целостная и структурированная модель.
Теория: Как это работает?
Работа с вложенными моделями базируется на использовании моделей внутри других моделей. Это достигается путем указания атрибута как экземпляра класса другой модели. Pydantic затем берет на себя обязанности проверить корректность данных на каждом уровне.
Ключевые моменты:
- Связывание моделей: одна модель может быть атрибутом другой.
- Рекурсивная проверка: Pydantic автоматически валидирует вложенные модели.
- Реализация через аннотации типов: используются аннотации типов Python для указания вложенных данных.
Пример простой вложенной модели
Начнем с создания простой структуры данных, где заказ (Order) содержит информацию о пользователе (User) и списке товаров (Item).
from pydantic import BaseModel
from typing import List
class User(BaseModel):
id: int
name: str
email: str
class Item(BaseModel):
id: int
name: str
price: float
class Order(BaseModel):
user: User
items: List[Item]
Здесь:
Userописывает пользователя.Itemописывает товар.Orderсодержит ссылку на пользователя и список товаров.
Теперь мы можем использовать Order для валидации данных, включающих вложенные структуры.
Пример использования
order_data = {
"user": {
"id": 1,
"name": "Иван Иванов",
"email": "ivan.ivanov@example.com"
},
"items": [
{"id": 101, "name": "Ноутбук", "price": 499.99},
{"id": 102, "name": "Мышь", "price": 9.99}
]
}
order = Order(**order_data)
print(order)
Вывод будет примерно таким:
user=User(id=1, name='Иван Иванов', email='ivan.ivanov@example.com')
items=[Item(id=101, name='Ноутбук', price=499.99), Item(id=102, name='Мышь', price=9.99)]
Если в данных будет ошибка, например, у товара не указан price, Pydantic выбросит исключение, указывающее, что поле price является обязательным.
Вложенные модели и валидация
Давайте посмотрим, как Pydantic справляется с ошибочными данными.
broken_order_data = {
"user": {
"id": 1,
"name": "Иван Иванов",
"email": "ivan.ivanov@example"
},
"items": [
{"id": 101, "name": "Ноутбук"},
{"id": 102, "name": "Мышь", "price": "девять"}
]
}
try:
broken_order = Order(**broken_order_data)
except Exception as e:
print(e)
Вывод:
1 validation error for Order
user -> email
value is not a valid email address (type=value_error.email)
items -> 0 -> price
field required (type=value_error.missing)
items -> 1 -> price
value is not a valid float (type=type_error.float)
Каждое ошибочное поле помечено детализированным сообщением об ошибке. Удобно, не так ли?
Работа с более сложными структурами
Например, заказ может включать не только пользователя и товары, но и данные о доставке. Создадим модель с дополнительным вложением.
class Address(BaseModel):
street: str
city: str
zip_code: str
class Shipping(BaseModel):
address: Address
delivery_date: str
class ExtendedOrder(BaseModel):
user: User
items: List[Item]
shipping: Shipping
Теперь данные будут выглядеть так:
extended_order_data = {
"user": {
"id": 1,
"name": "Иван Иванов",
"email": "ivan.ivanov@example.com"
},
"items": [
{"id": 101, "name": "Ноутбук", "price": 499.99},
{"id": 102, "name": "Мышь", "price": 9.99}
],
"shipping": {
"address": {
"street": "Улица Ленина, д.1",
"city": "Москва",
"zip_code": "101000"
},
"delivery_date": "2023-11-01"
}
}
order = ExtendedOrder(**extended_order_data)
print(order)
Ошибки и типичные проблемы
- Опечатки во вложенных данных: если поле вложенной модели опущено, это вызовет ошибку. Убедитесь, что вы передали все обязательные атрибуты.
- Неправильные типы: если данные имеют неправильный тип (например, строка вместо числа), Pydantic сразу выдаст ошибку.
- Слишком глубокая вложенность: оптимально избегать сложных и запутанных вложенных структур, так как это усложняет обработку.
Заключительные замечания
Вложенные модели — это жизненно важный инструмент для реализации сложных систем. Они помогают нам валидировать структуру даже самых замысловатых JSON, уменьшая вероятность обработки некорректных данных. С FastAPI и Pydantic ваша работа с данными становится не только мощной, но и простой.
В следующей лекции мы продолжим углубляться в тонкости валидации и научимся работать с обязательными и опциональными полями!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ