Оптимизация запросов на странице клиента

- Устранён N+1 для статусов заказов: добавлен select_related('status')
- Расчёт total_debt перенесён на сторону БД через aggregate с Greatest/Coalesce
- Избежана загрузка всех активных заказов в память для подсчёта долга
- Количество активных заказов теперь считается через count() без загрузки данных
- Ожидаемый эффект: минус 10+ запросов на страницу, быстрее рендер при большом количестве заказов
This commit is contained in:
2025-11-29 19:31:44 +03:00
parent e7ac4bd8a8
commit 29e47e7248

View File

@@ -2,7 +2,8 @@ from django.shortcuts import render, get_object_or_404, redirect
from django.contrib import messages
from django.core.paginator import Paginator
from django.core.exceptions import ValidationError, PermissionDenied
from django.db.models import Q
from django.db.models import Q, Sum, F, Value, DecimalField
from django.db.models.functions import Greatest, Coalesce
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from django.contrib.auth.decorators import login_required
@@ -86,9 +87,18 @@ def customer_detail(request, pk):
if customer.is_system_customer:
return render(request, 'customers/customer_system.html')
# Рассчитываем общий долг по активным заказам
active_orders = customer.orders.exclude(payment_status='paid')
total_debt = sum(order.amount_due for order in active_orders)
# Рассчитываем общий долг по активным заказам на стороне БД
total_debt_result = customer.orders.exclude(payment_status='paid').aggregate(
total_debt=Coalesce(
Sum(Greatest(F('total_amount') - F('amount_paid'), Value(0), output_field=DecimalField())),
Value(0),
output_field=DecimalField()
)
)
total_debt = total_debt_result['total_debt'] or Decimal('0')
# Количество активных заказов
active_orders_count = customer.orders.exclude(payment_status='paid').count()
# История транзакций кошелька (последние 20)
from .models import WalletTransaction
@@ -96,8 +106,8 @@ def customer_detail(request, pk):
customer=customer
).select_related('order', 'created_by').order_by('-created_at')[:20]
# История заказов с пагинацией
orders_list = customer.orders.all().order_by('-created_at')
# История заказов с пагинацией и оптимизацией запросов
orders_list = customer.orders.select_related('status').order_by('-created_at')
paginator = Paginator(orders_list, 10) # 10 заказов на страницу
page_number = request.GET.get('page')
orders_page = paginator.get_page(page_number)
@@ -105,7 +115,7 @@ def customer_detail(request, pk):
context = {
'customer': customer,
'total_debt': total_debt,
'active_orders_count': active_orders.count(),
'active_orders_count': active_orders_count,
'wallet_transactions': wallet_transactions,
'orders_page': orders_page,
}