Какие инструменты DRF и Django использовать для реализации бизнес-логики сохранения заказа?
Что проверяют
Умеете ли вы писать логику, которая выдерживает конкурентные запросы и частичные сбои, а не только CRUD из ModelViewSet. Заказ это списание остатков, фиксация цены и побочные действия, и всё должно быть атомарным. Следом спрашивают, что будет, если два покупателя одновременно берут последний товар.
Как отвечать
Разложите по слоям:
- сериализатор: вход и валидация в
validate_<field>иvalidate(), цена и пользователь вread_only_fields. Вложенные позиции DRF по умолчанию не записывает, их создают явно; - сервисная функция:
create_order(user, items)держит бизнес-логику, а неsave()модели и не сигналы. Так её проще тестировать и вызывать из админки или фоновой задачи; - транзакция: тело сервиса под
transaction.atomic(), одна неудачная позиция откатывает весь заказ; - остатки:
select_for_update()на строках товаров, блокировки в одном порядке поid, чтобы не ловить дедлоки. Или атомарныйfilter(pk=pk, stock__gte=qty).update(stock=F("stock") - qty)с проверкой, что обновилась одна строка; - снимок цены:
OrderItemхранит цену и количество на момент покупки вDecimalField, а не ссылку на текущую цену; - побочные действия: письмо и задача Celery уходят через
transaction.on_commit(); - повторы: ключ идемпотентности от клиента и
UniqueConstraint, чтобы двойной клик не создал два заказа; - view:
perform_create()передаётrequest.userв сервис, доступ черезpermission_classes.
Для тестов подойдут APITestCase на контракт и captureOnCommitCallbacks для отложенных действий.
Где спотыкаются
Делают сериализатор с fields = "__all__", и клиент сам присылает цену, статус или чужой user.
Читают остаток, сравнивают в Python и сохраняют без блокировки. Под нагрузкой два запроса продают последний товар дважды.
Шлют письмо или ставят задачу прямо внутри atomic. Транзакция откатилась, а покупателю уже пришло подтверждение заказа.