Схема запроса¶
Эта страница объясняет, как работает RequestModel и чем он отличается от обычного pydantic.BaseModel.
Что такое RequestModel?¶
RequestModel — подкласс pydantic.BaseModel, который переопределяет механизм создания объектов, чтобы принимать Django HttpRequest:
Оба стиля вызова равнозначны с точки зрения Pydantic:
# Стандартный Pydantic — по-прежнему работает
data = UserSchema(username="alice", email="alice@example.com")
# Новый стиль — передаёшь request напрямую
data = UserSchema(request)
Как это работает?¶
RequestModel использует кастомный метакласс, который перехватывает создание объекта. При вызове MySchema(request) Python вызывает type(MySchema).__call__(MySchema, request). Метакласс определяет, что первый аргумент — HttpRequest, извлекает данные и передаёт их в стандартный __init__ Pydantic:
# Упрощённые внутренности — ты это не пишешь
class _RequestModelMeta(type(BaseModel)):
def __call__(cls, *args, **kwargs):
if args and isinstance(args[0], HttpRequest):
data = extract_data(args[0], **kwargs) # (1)!
return super().__call__(**data) # (2)!
return super().__call__(*args, **kwargs) # (3)!
- Извлекаем плоский
dictиз запроса (см. Источники данных). - Вызываем стандартный
__init__Pydantic с извлечёнными данными. Здесь запускается полная валидация. - Фолбэк на стандартное создание объекта Pydantic, когда request не передан.
Никаких приватных API Pydantic
Метакласс наследуется от type(pydantic.BaseModel) — без приватных импортов.
Совместимость сохраняется между минорными версиями Pydantic v2.
Стандартный Pydantic работает как обычно¶
Поскольку RequestModel — правильный подкласс BaseModel, всё, что ты знаешь о Pydantic, применимо здесь:
from pydantic import Field, model_validator
from django_pydantic import RequestModel
class ProductSchema(RequestModel):
name: str = Field(min_length=1, max_length=100)
price: float = Field(gt=0)
quantity: int = Field(ge=0, default=0)
@model_validator(mode="after")
def check_stock(self):
if self.quantity == 0 and self.price < 1.0:
raise ValueError("Бесплатные товары должны иметь остаток > 0")
return self
Вложенные схемы¶
Вложенные Pydantic-модели работают для JSON-тела:
from pydantic import BaseModel
from django_pydantic import RequestModel
class AddressModel(BaseModel):
street: str
city: str
class OrderSchema(RequestModel):
product_id: int
quantity: int
address: AddressModel # вложенная, заполняется из JSON
curl -X POST /order/ \
-H "Content-Type: application/json" \
-d '{"product_id": 42, "quantity": 3, "address": {"street": "Ленина 1", "city": "Москва"}}'
Вложенные модели требуют JSON
Вложенные Pydantic-модели можно заполнить только из JSON-тела. HTML-форма по природе своей плоская и не может представлять вложенные структуры.
Переиспользование схем¶
Одна схема работает в нескольких вьюхах — это просто класс:
class PaginationSchema(RequestModel):
page: int = Field(ge=1, default=1)
page_size: int = Field(ge=1, le=100, default=20)
def article_list(request):
p = PaginationSchema(request)
qs = Article.objects.all()[(p.page - 1) * p.page_size : p.page * p.page_size]
...
def comment_list(request):
p = PaginationSchema(request)
...
model_dump и сериализация¶
RequestModel наследует все методы сериализации от BaseModel:
data = UserSchema(request)
data.model_dump() # → dict
data.model_dump_json() # → JSON-строка
data.model_fields_set # → множество полей, которые были явно переданы
Далее: Источники данных →