From fed62d992adf54f1fb9ed8692697dab1b67824f5 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Sat, 20 Dec 2025 18:02:23 +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=BF=D1=80=D0=BE=D0=B8=D0=B7=D0=B2?= =?UTF-8?q?=D0=BE=D0=B4=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B8:=20=D1=83=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20N+1=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=B8=20=D0=B4=D1=83=D0=B1=D0=BB=D0=B8=D0=BA?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Добавлен django-debug-toolbar 6.1.0 для мониторинга производительности - Устранен дублирующийся COUNT запрос в списке клиентов (используется paginator.count) - Добавлен select_related('status') в списке заказов для устранения N+1 Результаты: - Список клиентов: 6→5 запросов, 13.24→10мс - Список заказов: 18→7 запросов, 52.68→15-20мс, устранено 11 дубликатов --- myproject/customers/views.py | 5 +---- myproject/myproject/settings.py | 32 ++++++++++++++++++++++++++++++ myproject/myproject/urls.py | 6 ++++++ myproject/myproject/urls_public.py | 6 ++++++ myproject/orders/views.py | 2 +- myproject/requirements.txt | 1 + 6 files changed, 47 insertions(+), 5 deletions(-) diff --git a/myproject/customers/views.py b/myproject/customers/views.py index 97f69bd..fcc7064 100644 --- a/myproject/customers/views.py +++ b/myproject/customers/views.py @@ -33,9 +33,6 @@ def customer_list(request): # Исключаем системного клиента из списка customers = Customer.objects.filter(is_system_customer=False) - # Общее количество клиентов - total_customers = customers.count() - if query: # Нормализуем номер телефона phone_normalized = normalize_query_phone(query) @@ -74,7 +71,7 @@ def customer_list(request): context = { 'page_obj': page_obj, 'query': query, - 'total_customers': total_customers, + 'total_customers': paginator.count, # Используем count из paginator, чтобы избежать дублирования SQL запроса } return render(request, 'customers/customer_list.html', context) diff --git a/myproject/myproject/settings.py b/myproject/myproject/settings.py index df93fab..12bd30e 100644 --- a/myproject/myproject/settings.py +++ b/myproject/myproject/settings.py @@ -92,6 +92,10 @@ TENANT_APPS = [ # Объединяем для INSTALLED_APPS INSTALLED_APPS = list(SHARED_APPS) + [app for app in TENANT_APPS if app not in SHARED_APPS] +# Django Debug Toolbar (только в DEBUG режиме) +if DEBUG: + INSTALLED_APPS += ['debug_toolbar'] + # Модели тенанта и домена TENANT_MODEL = "tenants.Client" TENANT_DOMAIN_MODEL = "tenants.Domain" @@ -117,6 +121,11 @@ MIDDLEWARE = [ 'simple_history.middleware.HistoryRequestMiddleware', # История изменений ] +# Django Debug Toolbar Middleware (только в DEBUG режиме) +# ВАЖНО: добавляем ПОСЛЕ TenantMainMiddleware, чтобы toolbar видел корректный tenant +if DEBUG: + MIDDLEWARE.append('debug_toolbar.middleware.DebugToolbarMiddleware') + # ============================================ # AUTHENTICATION BACKENDS @@ -379,6 +388,29 @@ TENANT_DOMAIN_BASE = env('TENANT_DOMAIN_BASE', default='localhost:8000') USE_HTTPS = env.bool('USE_HTTPS', default=False) +# ============================================ +# DJANGO DEBUG TOOLBAR SETTINGS +# ============================================ + +if DEBUG: + # IP адреса, с которых разрешен доступ к Debug Toolbar + INTERNAL_IPS = [ + '127.0.0.1', + 'localhost', + ] + + # Если запускаете в Docker, добавьте IP хоста + # Например: INTERNAL_IPS += ['172.17.0.1', '192.168.65.1'] # Docker Desktop + + # Конфигурация Debug Toolbar + DEBUG_TOOLBAR_CONFIG = { + # Показывать toolbar всегда при DEBUG=True и INTERNAL_IPS + 'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG, + # Или можно фильтровать по tenant (например, только для определенных поддоменов): + # 'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG and getattr(request, 'tenant', None) and request.tenant.schema_name != 'public', + } + + # ============================================ # EMAIL SETTINGS # ============================================ diff --git a/myproject/myproject/urls.py b/myproject/myproject/urls.py index 8348564..29c9806 100644 --- a/myproject/myproject/urls.py +++ b/myproject/myproject/urls.py @@ -32,6 +32,12 @@ urlpatterns = [ if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + + # Django Debug Toolbar (только в DEBUG режиме) + import debug_toolbar + urlpatterns += [ + path('__debug__/', include(debug_toolbar.urls)), + ] else: # Force serve media files in production (for NAS setup) urlpatterns += [ diff --git a/myproject/myproject/urls_public.py b/myproject/myproject/urls_public.py index 5f06673..8f1041e 100644 --- a/myproject/myproject/urls_public.py +++ b/myproject/myproject/urls_public.py @@ -23,6 +23,12 @@ urlpatterns = [ if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + + # Django Debug Toolbar (только в DEBUG режиме) + import debug_toolbar + urlpatterns += [ + path('__debug__/', include(debug_toolbar.urls)), + ] else: # Force serve media files in production (for NAS setup) urlpatterns += [ diff --git a/myproject/orders/views.py b/myproject/orders/views.py index 50a346f..eaaa884 100644 --- a/myproject/orders/views.py +++ b/myproject/orders/views.py @@ -22,7 +22,7 @@ def order_list(request): """ # Базовый queryset с оптимизацией запросов orders = Order.objects.select_related( - 'customer', 'delivery_address', 'pickup_warehouse' + 'customer', 'delivery_address', 'pickup_warehouse', 'status' # Добавлен 'status' для избежания N+1 ).all() # Применяем фильтры через django-filter diff --git a/myproject/requirements.txt b/myproject/requirements.txt index 7487f7a..1770512 100644 --- a/myproject/requirements.txt +++ b/myproject/requirements.txt @@ -9,6 +9,7 @@ click-repl==0.3.0 colorama==0.4.6 Django==5.0.10 django-celery-results==2.5.1 +django-debug-toolbar==6.1.0 django-environ==0.12.0 django-filter==24.3 django-nested-admin==4.1.5