← Назад к вопросам

Как реализована сериализация данных в FastAPI?

2.3 Middle🔥 181 комментариев
#FastAPI и Flask#REST API и HTTP

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Сериализация данных в FastAPI

Сериализация — это процесс преобразования объектов Python в формат, понятный клиентам (обычно JSON). FastAPI использует Pydantic для автоматической сериализации.

1. Основы с Pydantic

from pydantic import BaseModel
from fastapi import FastAPI
from typing import Optional
from datetime import datetime

app = FastAPI()

class User(BaseModel):
    id: int
    name: str
    email: str
    age: Optional[int] = None
    created_at: datetime = datetime.now()

@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
    return User(
        id=user_id,
        name="Alice",
        email="alice@example.com",
        age=30
    )

Ответ будет автоматически сериализован в JSON:

{
  "id": 1,
  "name": "Alice",
  "email": "alice@example.com",
  "age": 30,
  "created_at": "2024-03-22T10:30:00"
}

2. Сложные типы данных

from typing import List, Dict
from decimal import Decimal

class Address(BaseModel):
    street: str
    city: str
    country: str
    zip_code: Optional[str] = None

class Product(BaseModel):
    id: int
    name: str
    price: Decimal  # Точные денежные значения
    tags: List[str]  # Список
    metadata: Dict[str, str]  # Словарь
    address: Address  # Вложенный объект

@app.post("/products", response_model=Product)
async def create_product(product: Product):
    return product

Читаемый и пишущий формат JSON:

{
  "id": 1,
  "name": "Laptop",
  "price": "999.99",
  "tags": ["electronics", "computers"],
  "metadata": {"brand": "Dell", "color": "black"},
  "address": {
    "street": "123 Main St",
    "city": "NYC",
    "country": "USA",
    "zip_code": "10001"
  }
}

3. Валидация данных

from pydantic import Field, validator, EmailStr

class User(BaseModel):
    id: int = Field(..., gt=0, description="User ID must be positive")
    name: str = Field(..., min_length=1, max_length=100)
    email: EmailStr  # Автоматическая валидация email
    age: int = Field(None, ge=0, le=150)
    
    @validator('name')
    @classmethod
    def name_must_contain_space(cls, v):
        if ' ' not in v:
            raise ValueError('Name must contain space')
        return v.title()

# При отправке неправильных данных FastAPI вернёт 422 с деталями ошибок

4. Исключение полей из сериализации

class UserCreate(BaseModel):
    name: str
    email: str
    password: str  # Не должен возвращаться клиенту
    
    class Config:
        exclude = {'password'}  # Исключить из ответа

class UserResponse(BaseModel):
    id: int
    name: str
    email: str
    
    class Config:
        exclude_unset = True  # Исключить поля, не установленные явно
        exclude_none = True   # Исключить None значения

@app.post("/users", response_model=UserResponse)
async def create_user(user: UserCreate):
    # password не будет в ответе
    return {"id": 1, "name": user.name, "email": user.email}

5. Разные модели для входа и выхода

class UserCreate(BaseModel):
    name: str
    email: str
    password: str

class User(BaseModel):
    id: int
    name: str
    email: str
    created_at: datetime

@app.post("/users", response_model=User)
async def create_user(user_data: UserCreate):
    # password из UserCreate не попадёт в ответ
    # Вместо этого вернётся User с нужными полями
    return {
        "id": 1,
        "name": user_data.name,
        "email": user_data.email,
        "created_at": datetime.now()
    }

6. Списки и коллекции

class User(BaseModel):
    id: int
    name: str

@app.get("/users", response_model=List[User])
async def get_users():
    return [
        {"id": 1, "name": "Alice"},
        {"id": 2, "name": "Bob"},
    ]

# Ответ
[
  {"id": 1, "name": "Alice"},
  {"id": 2, "name": "Bob"}
]

7. Сериализация с преобразованиями

from pydantic import field_serializer

class User(BaseModel):
    id: int
    name: str
    created_at: datetime
    
    @field_serializer('created_at')
    def serialize_datetime(self, value):
        return value.isoformat()  # ISO формат даты
    
    @field_serializer('name')
    def serialize_name(self, value):
        return value.upper()  # Все заглавные буквы

user = User(id=1, name="alice", created_at=datetime.now())
print(user.model_dump())  # {'id': 1, 'name': 'ALICE', 'created_at': '2024-03-22T...'}

8. Пользовательские сериализаторы

from pydantic import ConfigDict

class User(BaseModel):
    id: int
    name: str
    password: str
    
    model_config = ConfigDict(
        json_schema_extra={
            "example": {
                "id": 1,
                "name": "Alice",
                "password": "secret"
            }
        }
    )

# Получить JSON схему
print(User.model_json_schema())

9. Обработка исключений сериализации

from fastapi.responses import JSONResponse

class CustomException(Exception):
    def __init__(self, status_code: int, detail: str):
        self.status_code = status_code
        self.detail = detail

@app.exception_handler(CustomException)
async def custom_exception_handler(request, exc):
    return JSONResponse(
        status_code=exc.status_code,
        content={"error": exc.detail}
    )

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    if user_id < 0:
        raise CustomException(status_code=400, detail="Invalid user ID")
    return {"id": user_id, "name": "Alice"}

10. Оптимизация сериализации

from pydantic import BaseModel, ConfigDict

class User(BaseModel):
    model_config = ConfigDict(
        from_attributes=True,  # Совместимость с ORM моделями (Django, SQLAlchemy)
        validate_assignment=True,  # Валидация при изменении атрибутов
    )
    
    id: int
    name: str

# Быстрая сериализация
user = User(id=1, name="Alice")
json_str = user.model_dump_json()  # Прямо в JSON строку
json_dict = user.model_dump()      # В словарь

# С исключением полей
json_dict = user.model_dump(
    exclude={"password"},
    exclude_none=True,
    exclude_unset=True
)

Best Practices

1. Разные модели: используйте отдельные модели для входа и выхода 2. Валидация: определяйте все ограничения в Pydantic 3. Безопасность: исключайте чувствительные поля (пароли) из ответов 4. Типизация: всегда указывайте точные типы полей 5. Документация: используйте Field() для описания параметров 6. Обработка ошибок: перехватывайте ошибки валидации красиво 7. ORM интеграция: используйте from_attributes=True для работы с моделями БД

Как реализована сериализация данных в FastAPI? | PrepBro