В FastAPI для работы с данными используется библиотека Pydantic, которая предоставляет удобные инструменты для валидации и сериализации данных. В этой статье мы погрузимся в более сложные аспекты работы с Pydantic: создание вложенных моделей, использование продвинутой валидации и управление конфигурацией приложения с помощью BaseSettings. Мы также создадим API с использованием вложенных Pydantic-моделей и параметров окружения.
Валидация в Pydantic
Pydantic делает валидацию данных простым и удобным процессом. Он автоматически проверяет типы данных, значения и даже позволяет нам использовать свои собственные методы валидации для более сложных сценариев.
Рассмотрим пример модели, которая принимает данные о пользователе и проверяет, что возраст находится в пределах от 18 до 100 лет:
from pydantic import BaseModel, validator
class User(BaseModel):
name: str
age: int
@validator('age')
def check_age(cls, v):
if not (18 <= v <= 100):
raise ValueError('Age must be between 18 and 100')
return v
Пояснение к коду:
- @validator(‘age’) — это декоратор, который добавляет валидацию для поля age.
- Внутри метода мы проверяем, что возраст находится в пределах от 18 до 100 лет. Если условие не выполнено, мы выбрасываем ошибку.
Эти валидаторы можно использовать для любых типов данных, создавая более гибкие и точные схемы.
Создание сложных схем
Теперь давайте создадим более сложную модель с вложенными структурами. Например, нам нужно описать сущность заказа, который состоит из пользователя, товара и количества.
from pydantic import BaseModel
from typing import List
class Product(BaseModel):
name: str
price: float
class Order(BaseModel):
user_name: str
products: List[Product]
total_amount: float
Пояснение к коду:
- Product — это модель, которая описывает товар с именем и ценой.
- Order — это модель для заказа, которая включает имя пользователя, список продуктов и общую сумму заказа.
- Мы используем List[Product], чтобы указать, что заказ может включать несколько товаров.
Валидация вложенных данных
Pydantic автоматически валидирует вложенные модели, такие как список товаров. Например, если мы передадим неправильные данные (например, цену товара в виде строки), Pydantic выбросит ошибку валидации.
order_data = {
"user_name": "John Doe",
"products": [{"name": "Laptop", "price": "1000"}], # Здесь ошибка: цена — строка, а не число
"total_amount": 1000
}
order = Order(**order_data) # Pydantic выбросит ошибку валидации
Настройка конфигурации моделей
Пример: Преобразование данных
Предположим, что мы хотим преобразовать все имена в модели в верхний регистр перед сохранением.
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
class Config:
# Это настройка для сериализации данных
anystr_upper = True # Преобразуем все строки в верхний регистр
Пояснение:
- Config — это специальный класс, который используется для настройки поведения модели.
- С помощью anystr_upper = True мы говорим, что все строки в модели должны быть преобразованы в верхний регистр.
Когда мы создадим объект User и выведем его данные, имя будет в верхнем регистре:
user = User(name="john doe", age=30)
print(user.name) # JOHN DOE
Использование BaseSettings для управления конфигурацией приложения
BaseSettings — это специальный класс в Pydantic, предназначенный для управления параметрами конфигурации, которые обычно хранятся в файлах .env или переменных окружения. Это полезно, когда вам нужно настроить приложение в разных окружениях (например, в продакшн и в разработке).
Пример: Управление конфигурацией через переменные окружения
from pydantic import BaseSettings
class Settings(BaseSettings):
app_name: str = "My FastAPI App"
debug: bool = True
database_url: str
class Config:
env_file = ".env" # Путь к файлу с переменными окружения
env_file_encoding = "utf-8"
# Загружаем настройки из файла .env
settings = Settings()
print(settings.app_name)
print(settings.debug)
print(settings.database_url)
Пояснение:
- BaseSettings — это базовый класс для работы с настройками.
- Мы создаем модель, которая загружает переменные окружения из файла .env. Например:
DATABASE_URL=postgresql://user:password@localhost/dbname
Практика: Создание API с вложенными Pydantic-моделями и настройкой параметров окружения
Шаг 1: Создадим файл .env:
DATABASE_URL=postgresql://user:password@localhost/mydatabase
DEBUG=True
Шаг 2: Реализуем API с использованием вложенных моделей и конфигурации:
from fastapi import FastAPI
from pydantic import BaseModel, BaseSettings
from typing import List
class Product(BaseModel):
name: str
price: float
class Order(BaseModel):
user_name: str
products: List[Product]
total_amount: float
class Settings(BaseSettings):
app_name: str = "Order API"
debug: bool = True
database_url: str
class Config:
env_file = ".env"
app = FastAPI()
# Загружаем настройки
settings = Settings()
@app.get("/orders/{order_id}")
def get_order(order_id: int):
# Здесь мы могли бы подключиться к базе данных и получить заказ
return {"order_id": order_id, "message": "Order details fetched successfully!"}
@app.post("/create-order/")
def create_order(order: Order):
# Здесь мы могли бы сохранить заказ в базе данных
return {"message": "Order created successfully!", "order": order.dict()}
if __name__ == "__main__":
print(f"App Name: {settings.app_name}")
print(f"Database URL: {settings.database_url}")
Заключение
Pydantic — мощный инструмент для работы с валидацией и сериализацией данных в FastAPI. Мы научились создавать сложные схемы, использовать продвинутую валидацию и управлять конфигурацией приложения через переменные окружения. Эти техники позволяют строить гибкие и надежные API, которые легко масштабируются и поддерживаются.