Код-ревью Middle Django: устройство обновлено
Код-ревью Django-вьюхи
Вопрос
Найдите проблемы во вьюхе, которая показывает заказ и отмечает его просмотренным.
from django.http import JsonResponse
from .models import Order
_cache = {}
def order_view(request, pk):
order = Order.objects.get(pk=pk)
if request.GET.get('mark_seen'):
order.seen = True
order.save()
items = []
for item in order.items.all():
items.append({
'name': item.product.name,
'price': str(item.price),
})
_cache[pk] = items
return JsonResponse({
'id': order.id,
'owner_email': order.owner.email,
'items': items,
})
Коротко
Исправленная версия: Отметку о просмотре выносим в отдельный POST-эндпоинт. Глобальный словарь убираем: в процессе gunicorn он живёт до перезапуска, растёт и не виден другим воркерам.
Что должен найти ревьюер
- Ошибкастрока 8
Order.objects.getпри отсутствии заказа даёт 500DoesNotExist; нуженget_object_or_404 - Безопасностьстрока 8Нет проверки владельца: любой пользователь откроет чужой заказ по id (IDOR). Фильтровать по
owner=request.userи требовать вход - Ошибкастрока 9Изменение данных по GET-запросу: GET должен быть безопасным, его повторяют браузеры, кеши и краулеры; нужен POST
- Производительностьстрока 15N+1: для каждой позиции отдельный запрос за
product; нуженselect_related("product")илиprefetch_related - Ошибкастрока 18Глобальный словарь как кеш растёт без ограничений и не делится между процессами; использовать кеш Django с TTL или убрать
Разбор
Исправленная версия:
@login_required
@require_GET
def order_view(request, pk):
order = get_object_or_404(
Order.objects.select_related('owner'),
pk=pk, owner=request.user,
)
items = [
{'name': i.product.name, 'price': str(i.price)}
for i in order.items.select_related('product')
]
return JsonResponse({'id': order.id, 'items': items})
Отметку о просмотре выносим в отдельный POST-эндпоинт. Глобальный словарь убираем: в процессе gunicorn он живёт до перезапуска, растёт и не виден другим воркерам. Если email владельца не нужен клиенту, его тоже не стоит отдавать.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.