← Назад к вопросам
Как реализована сериализация данных в 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 для работы с моделями БД