Модель Pydantic в FastAPI

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


Что такое Pydantic

Pydantic — это библиотека Python для проверки данных. Её основная философия:определяйте структуры данных с помощью аннотаций типов Python, а Pydantic автоматически выполняет проверку и преобразованиеВ FastAPI Pydantic в основном используется для:

НазначениеОписание
Валидация тела запросаАвтоматически проверять, соответствуют ли JSON-данные, отправленные клиентами, определению модели
Сериализация тела ответаАвтоматически преобразовывать данные модели в JSON-ответы
Автоматическая документацияПоля модели, типы и правила валидации автоматически отображаются в документации API
Поддержка редактораАтрибуты модели получают полное автодополнение в редакторе

Определение моделей Pydantic

Создание наследованияBaseModelклассов, которые объявляют поля с использованием стандартных типов Python:

Пример

from pydantic import BaseModel


class Item(BaseModel):
    name: str               # Обязательно: название продукта
    description: str | None = None  # Необязательно: описание продукта
    price: float            # Обязательно: цена продукта
    tax: float | None = None        # Необязательно: налог

Является ли поле обязательным, зависит от того, есть ли у него значение по умолчанию:

FieldsСпособ объявленияОбязательно?
namename: strОбязательный
descriptiondescription: str | None = NoneOptional
priceprice: floatОбязательный
taxtax: float | None = NoneOptional

Используйте модели Pydantic

В качестве тела запроса

Наиболее распространённый вариант использования — объявление модели в качестве параметра функции операции пути:

Пример

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.post("/items/")
async def create_item(item: Item):
    # FastAPI автоматически проверяет тело запроса и после успешной проверки присваивает его параметру item
    return item

Доступ к данным модели и работа с ними

Пример

@app.post("/items/")
async def create_item(item: Item):
    # Доступ к атрибутам модели
    print(item.name)       # Прямой доступ к атрибутам
    print(item.price)      # Редактор обеспечивает автодополнение

    # Сериализация в словарь
    item_dict = item.model_dump()
    print(item_dict)       # {"name": "Foo", "description": None, "price": 45.2, "tax": None}

    # Сериализация в строку JSON
    item_json = item.model_dump_json()
    print(item_json)       # '{"name":"Foo","description":null,"price":45.2,"tax":null}'

    return item_dict

Использование Pydantic v2model_dump()иmodel_dump_json()Заменяет v1dict()иjson()метод. Новый метод имеет лучшую производительность (реализован на Rust под капотом).


Пример валидации модели

Когда данные, отправленные клиентом, не соответствуют определению модели, FastAPI возвращает подробные ошибки валидации:

Пример

# Клиент отправил данные, в которых отсутствуют обязательные поля
POST /items/
{
    "description": "отсутствуют имя и цена"
}

# Ошибка валидации ответа FastAPI
{
    "detail": [
        {
            "type": "missing",
            "loc": ["body", "name"],
            "msg": "Обязательное поле",
            "input": {"description": "отсутствуют имя и цена"}
        },
        {
            "type": "missing",
            "loc": ["body", "price"],
            "msg": "Обязательное поле",
            "input": {"description": "отсутствуют имя и цена"}
        }
    ]
}

Если отправлены данные неверного типа:

// price 应该是数字,但传了字符串
{
    "name": "Foo",
    "price": "not a number"
}

// FastAPI 返回的错误
{
    "detail": [
        {
            "type": "float_parsing",
            "loc": ["body", "price"],
            "msg": "Input should be a valid number, unable to parse string as a number",
            "input": "not a number"
        }
    ]
}

Общие методы Pydantic v2

Методыv2 (рекомендуется)v1 (устарело)Описание
Сериализация в словарьitem.model_dump()item.dict()Преобразование модели в словарь Python
Сериализация в JSONitem.model_dump_json()item.json()Преобразование модели в строку JSON
Создание из словаряItem.model_validate(data)Item.parse_obj(data)Создание и проверка модели из словаря
Создание из JSONItem.model_validate_json(json_str)Item.parse_raw(json_str)Создание модели из строки JSON
Получение JSON SchemaItem.model_json_schema()Item.schema()Получение JSON Schema модели

Конфигурация модели (model_config)

Использование Pydantic v2model_configЗаменяет v1ConfigВнутренний класс:

Пример

from pydantic import BaseModel, ConfigDict


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

    # Метод конфигурации Pydantic v2
    model_config = ConfigDict(
        json_schema_extra={  # Отображение примеров в документации API
            "examples": [
                {
                    "name": "Foo",
                    "price": 35.4
                }
            ]
        }
    )

В Pydantic v2,orm_mode = Trueизменено наfrom_attributes = True,schema_extraизменено наjson_schema_extra,allow_population_by_field_nameизменено наpopulate_by_name。


Наследование моделей

Модели Pydantic поддерживают наследование, что упрощает создание входных и выходных моделей:

Пример

from pydantic import BaseModel, EmailStr


# Базовая модель
class UserBase(BaseModel):
    username: str       # Обязательно
    email: EmailStr     # Обязательно, автоматически проверяет формат электронной почты
    full_name: str | None = None  # Необязательно


# Входная модель для создания пользователя (включая пароль)
class UserCreate(UserBase):
    password: str       # Обязательно


# Выходная модель для возврата информации о пользователе (не включает пароль)
class UserOut(UserBase):
    id: int             # Генерируется сервером


# Пример использования
@app.post("/users/", response_model=UserOut)
async def create_user(user: UserCreate):
    # Функция получает UserCreate (с паролем), но ответ использует UserOut (без пароля)
    # Таким образом, пароль не появится в ответе API.
    return {"id": 1, **user.model_dump(exclude={"password"})}

Использование разных моделей ввода и вывода — важное средство защиты конфиденциальных данных. Никогда не возвращайте конфиденциальные поля, такие как пароли, в ответах API.


Итог

Ключевые моменты моделей Pydantic:

  • ИспользованиеBaseModelОпределяйте модели данных, объявляя поля стандартными типами Python
  • Поля со значениями по умолчанию необязательны, поля без значений по умолчанию обязательны
  • использование v2model_dump()、model_validate()и другие новые методы
  • Создавайте разные модели ввода/вывода с помощью наследования моделей для защиты конфиденциальных данных
  • Вся валидация и документация автоматически — просто объявите типы один раз
Другие расширения