Выбор ответа Senior Django ORM и N+1 обновлено
Задвоение сумм при нескольких annotate
Вопрос
Customer.objects.annotate(orders=Count("order"), paid=Sum("payment__amount")) даёт завышенные суммы оплат. Почему?
Попробуйте сами
Выберите вариант, и откроется разбор.
Показать ответ и разбор
Коротко
Правильный ответ: Два JOIN «ко многим» перемножают строки, и оплаты считаются повторно. Django строит один запрос с JOIN к заказам и к оплатам.
Варианты ответа
- У
Sumошибка округления при суммировании Decimal в PostgreSQL CountиSumнельзя использовать в одномannotate, нужен второй вызов- Нужно добавить
order_by, иначе группировка идёт по случайному полю - Два JOIN «ко многим» перемножают строки, и оплаты считаются повторноправильный ответ
Разбор
Django строит один запрос с JOIN к заказам и к оплатам. Для клиента с 3 заказами и 2 оплатами получится 6 строк, и сумма оплат утроится. Count(..., distinct=True) спасает подсчёт, но не сумму. Надёжное решение: подзапросы через Subquery и OuterRef с агрегацией или отдельные запросы. order_by и округление тут ни при чём.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.