Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Вложенные модели и композиции
nested_models

Вложенные модели и композиции

Создание сложных структур данных через вложенные модели, списки моделей, опциональные поля.

Вложенные модели и композиции

Сложные структуры данных строятся из простых моделей как из конструктора

#Базовая композиция

Pydantic позволяет вкладывать модели друг в друга:

from pydantic import BaseModel class Address(BaseModel): street: str city: str zip_code: str country: str class User(BaseModel): name: str email: str address: Address # вложенная модель # Создание с вложенной моделью address = Address( street="123 Main St", city="New York", zip_code="10001", country="USA" ) user = User(name="Alice", email="alice@example.com", address=address) # Или сразу dict (автоматическая валидация) user = User( name="Alice", email="alice@example.com", address={ "street": "123 Main St", "city": "New York", "zip_code": "10001", "country": "USA" } )

Pydantic автоматически создаст вложенную модель из словаря.

#Списки моделей

from typing import List class Ingredient(BaseModel): name: str quantity: float unit: str class Recipe(BaseModel): title: str servings: int ingredients: list[Ingredient] # список моделей # Создание recipe = Recipe( title="Pancakes", servings=4, ingredients=[ {"name": "Flour", "quantity": 200, "unit": "g"}, {"name": "Milk", "quantity": 300, "unit": "ml"}, {"name": "Eggs", "quantity": 2, "unit": "pcs"} ] ) # Доступ к вложенным данным print(recipe.ingredients[0].name) # "Flour" print(len(recipe.ingredients)) # 3

#Глубокая вложенность

Модели могут быть вложены на любую глубину:

class Coordinate(BaseModel): lat: float lon: float class Location(BaseModel): name: str coordinate: Coordinate class Event(BaseModel): title: str location: Location organizer: User # модель User с Address из предыдущего примера # Глубокая вложенность event = Event( title="Python Conference", location={ "name": "Convention Center", "coordinate": {"lat": 40.7128, "lon": -74.0060} }, organizer={ "name": "Alice", "email": "alice@example.com", "address": { "street": "123 Main St", "city": "New York", "zip_code": "10001", "country": "USA" } } ) # Доступ print(event.location.coordinate.lat) # 40.7128 print(event.organizer.address.city) # "New York"

#Опциональные вложенные модели

from typing import Optional class Company(BaseModel): name: str industry: str class User(BaseModel): name: str email: str company: Optional[Company] = None # необязательная вложенная модель # Без компании user1 = User(name="Alice", email="alice@example.com") print(user1.company) # None # С компанией user2 = User( name="Bob", email="bob@example.com", company={"name": "TechCorp", "industry": "Software"} ) print(user2.company.name) # "TechCorp"

#Словари с моделями

class Permission(BaseModel): can_read: bool can_write: bool can_delete: bool class Role(BaseModel): name: str permissions: dict[str, Permission] # словарь моделей role = Role( name="Admin", permissions={ "users": {"can_read": True, "can_write": True, "can_delete": True}, "posts": {"can_read": True, "can_write": True, "can_delete": False} } ) print(role.permissions["users"].can_delete) # True

#Union вложенных моделей

from typing import Union, Literal class Cat(BaseModel): pet_type: Literal["cat"] name: str meows: int class Dog(BaseModel): pet_type: Literal["dog"] name: str barks: float class Owner(BaseModel): name: str pet: Union[Cat, Dog] # может быть Cat или Dog # С котом owner1 = Owner( name="Alice", pet={"pet_type": "cat", "name": "Whiskers", "meows": 10} ) # С собакой owner2 = Owner( name="Bob", pet={"pet_type": "dog", "name": "Buddy", "barks": 5.5} )

#Методы для вложенных моделей

#model_dump с вложенностью

user = User( name="Alice", email="alice@example.com", address={ "street": "123 Main St", "city": "New York", "zip_code": "10001", "country": "USA" } ) # Полная сериализация data = user.model_dump() # {'name': 'Alice', 'email': 'alice@example.com', # 'address': {'street': '123 Main St', 'city': 'New York', ...}} # С исключением вложенного поля data = user.model_dump(exclude={'address': True}) # {'name': 'Alice', 'email': 'alice@example.com'} # С исключением полей во вложенной модели data = user.model_dump(exclude={'address': {'zip_code'}}) # address без zip_code

#model_validate с вложенностью

# Валидация из dict с вложенными dict data = { "name": "Alice", "email": "alice@example.com", "address": { "street": "123 Main St", "city": "New York", "zip_code": "10001", "country": "USA" } } user = User.model_validate(data) # Валидация из JSON import json json_str = json.dumps(data) user = User.model_validate_json(json_str)

#Рекурсивные модели

Модель может ссылаться сама на себя:

from typing import Optional, List from __future__ import annotations # для рекурсивных ссылок class TreeNode(BaseModel): value: int left: Optional[TreeNode] = None right: Optional[TreeNode] = None # Создание дерева tree = TreeNode( value=1, left=TreeNode(value=2, left=TreeNode(value=4)), right=TreeNode(value=3) )

Для рекурсивных моделей в Pydantic v2 используйте from __future__ import annotations или строковую ссылку:

class Category(BaseModel): name: str subcategories: list['Category'] = []

#Мини-проект: Модель заказа интернет-магазина

Создайте структуру моделей для заказа:

from pydantic import BaseModel, Field from datetime import datetime from typing import List, Optional from decimal import Decimal # OrderItem: товар в заказе # - product_id: int # - name: str # - quantity: int (положительное) # - price: Decimal (положительная) # - discount: float (0-1, по умолчанию 0) # ShippingAddress # - street: str # - city: str # - zip_code: str # - country: str # Order: заказ # - order_id: int # - items: список OrderItem # - shipping_address: ShippingAddress # - billing_address: Optional[ShippingAddress] (если None, совпадает с shipping) # - created_at: datetime (по умолчанию сейчас) # - status: Literal["pending", "processing", "shipped", "delivered", "cancelled"] # Добавьте метод total_price() через @computed_field для подсчёта общей суммы

Пример использования:

order = Order( order_id=1, items=[ {"product_id": 1, "name": "Mouse", "quantity": 2, "price": Decimal("29.99")}, {"product_id": 2, "name": "Keyboard", "quantity": 1, "price": Decimal("79.99")} ], shipping_address={ "street": "123 Main St", "city": "New York", "zip_code": "10001", "country": "USA" }, status="pending" ) print(order.total_price) # 2*29.99 + 1*79.99 = 139.97

Далее: Валидация полей: Field и валидаторы