Тело запроса: Pydantic модели

Тело запроса: Pydantic модели FastAPI

Привет! FastAPI использует Pydantic для валидации данных. Это одна из самых мощных фишек фреймворка — данные автоматически проверяются, преобразуются и документируются.

В этой статье мы разберём:

  • Что такое Pydantic модели
  • Создание моделей
  • Валидация данных
  • Вложенные модели
  • Опциональные поля

Что нужно знать перед началом

Для этого урока тебе понадобится:

  • Установленный FastAPI
  • Базовое понимание классов Python

Совет: Pydantic — это основа FastAPI. Без него невозможно представить работу с данными.

Основная часть

Что такое Pydantic

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

from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int
    email: str

Совет: Pydantic автоматически валидирует типы и преобразует данные.

Создание модели

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float
    description: str = None  # Опциональное поле
    tax: float = 0.0

@app.post("/items/")
def create_item(item: Item):
    return {"item": item}

Совет: Поля со значениями по умолчанию становятся опциональными.

Валидация типов

Pydantic автоматически проверяет типы.

class User(BaseModel):
    name: str
    age: int
    is_active: bool = True

# Правильно
user = User(name="Анна", age=25, is_active=True)

# Ошибка! age должен быть int
# user = User(name="Анна", age="25")

Опциональные поля

from typing import Optional

class User(BaseModel):
    name: str
    age: Optional[int] = None
    city: Optional[str] = None

Вложенные модели

class Address(BaseModel):
    street: str
    city: str
    zip_code: str

class User(BaseModel):
    name: str
    age: int
    address: Address

@app.post("/users/")
def create_user(user: User):
    return {"user": user}

Пример запроса:

{
    "name": "Анна",
    "age": 25,
    "address": {
        "street": "ул. Ленина, 1",
        "city": "Москва",
        "zip_code": "123456"
    }
}

Списки в моделях

from typing import List

class Order(BaseModel):
    id: int
    items: List[str]
    prices: List[float]

@app.post("/orders/")
def create_order(order: Order):
    return {"order": order}

Пример запроса:

{
    "id": 1,
    "items": ["Ноутбук", "Телефон"],
    "prices": [1000.0, 500.0]
}

Валидация полей

from pydantic import BaseModel, Field

class User(BaseModel):
    name: str = Field(..., min_length=2, max_length=50)
    age: int = Field(..., ge=0, le=120)
    email: str = Field(..., regex=r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")

@app.post("/users/")
def create_user(user: User):
    return {"user": user}

Параметры Field:

ПараметрНазначение
min_lengthМинимальная длина
max_lengthМаксимальная длина
geБольше или равно
leМеньше или равно
regexРегулярное выражение
defaultЗначение по умолчанию

Валидация через валидаторы

from pydantic import BaseModel, validator

class User(BaseModel):
    name: str
    password: str

    @validator('password')
    def validate_password(cls, value):
        if len(value) < 6:
            raise ValueError('Пароль должен быть не менее 6 символов')
        return value

Полный пример

from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import Optional, List

app = FastAPI()

class Address(BaseModel):
    street: str
    city: str
    zip_code: str

class UserCreate(BaseModel):
    name: str = Field(..., min_length=2, max_length=50)
    age: int = Field(..., ge=0, le=120)
    email: str = Field(..., regex=r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
    phone: Optional[str] = None
    address: Optional[Address] = None
    tags: List[str] = []

@app.post("/users/")
def create_user(user: UserCreate):
    return {
        "message": "Пользователь создан",
        "user": user
    }

@app.post("/users/bulk/")
def create_users(users: List[UserCreate]):
    return {"message": f"Создано {len(users)} пользователей"}

Задачи для закрепления

Задача 1. Создай модель Product с полями: namepricedescription.

Задача 2. Добавь валидацию: price >= 0.

Задача 3. Создай модель Order с вложенной моделью Product.

Задача 4. Создай эндпоинт для создания заказа.

Задача 5. Добавь опциональное поле discount в модель Product.

Ответы:

Задача 1.

class Product(BaseModel):
    name: str
    price: float
    description: Optional[str] = None

Задача 2.

class Product(BaseModel):
    name: str
    price: float = Field(..., ge=0)
    description: Optional[str] = None

Задача 3.

class Product(BaseModel):
    name: str
    price: float

class Order(BaseModel):
    id: int
    products: List[Product]

Задача 4.

@app.post("/orders/")
def create_order(order: Order):
    return {"order": order}

Задача 5.

class Product(BaseModel):
    name: str
    price: float
    discount: Optional[float] = 0.0

Нюансы и подводные камни

  • Pydantic модели автоматически валидируют данные при получении.
  • Ошибки валидации возвращают статус 422.
  • Field позволяет добавлять дополнительные проверки (min_length, ge, le, regex).
  • Можно создавать вложенные модели и списки моделей.
  • Валидаторы (@validator) выполняются в порядке объявления полей.
  • Pydantic автоматически преобразует типы (например, строку в число).
  • Optional с None делает поле необязательным.

Частые ошибки и как их избежать

Ошибка 1: Забыл импортировать Field

from pydantic import BaseModel, Field

Ошибка 2: Неправильная валидация вложенных моделей

Проверяй вложенные модели отдельно.

Ошибка 3: Использование @validator без values для кросс-полей

Для проверки нескольких полей используй values в валидаторе.

Шпаргалка

Что нужноКак пишется
Модельclass User(BaseModel):
Обязательное полеname: str
Опциональное полеage: Optional[int] = None
Вложенная модельaddress: Address
Списокitems: List[str]
ВалидацияField(..., min_length=2)
Валидатор@validator('field')

Заключение

Сегодня мы:

  • Узнали, что такое Pydantic модели
  • Научились создавать модели
  • Добавили валидацию
  • Использовали вложенные модели

КВИЗ

Что дальше?

Оцените статью
IMI-DS - PYTHON LERNEN
Содержание
Оглавление ×