From 29e47e724802194b65099e3efafbe7c8a96df9d7 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Sat, 29 Nov 2025 19:31:44 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=BF=D1=82=D0=B8=D0=BC=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=BD=D0=B0=20=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=86=D0=B5=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Устранён N+1 для статусов заказов: добавлен select_related('status') - Расчёт total_debt перенесён на сторону БД через aggregate с Greatest/Coalesce - Избежана загрузка всех активных заказов в память для подсчёта долга - Количество активных заказов теперь считается через count() без загрузки данных - Ожидаемый эффект: минус 10+ запросов на страницу, быстрее рендер при большом количестве заказов --- myproject/customers/views.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/myproject/customers/views.py b/myproject/customers/views.py index f241d2b..368e0ba 100644 --- a/myproject/customers/views.py +++ b/myproject/customers/views.py @@ -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, }