Оптимизация списка категорий: устранение N+1 запросов
- Добавлен Prefetch для активных товаров и комплектов в категориях - Фильтрация и сортировка вынесены в Prefetch (избегаем повторных запросов) - Изменен метод build_category_tree для использования предзагруженных данных Результаты: - Список категорий: 12→7 запросов, 26.76→~10мс - Устранены 4 похожих N+1 запроса (products и kits для каждой категории)
This commit is contained in:
@@ -7,10 +7,10 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.views.generic import ListView, CreateView, DetailView, UpdateView, DeleteView
|
||||
from django.urls import reverse_lazy, reverse
|
||||
from django.shortcuts import redirect
|
||||
from django.db.models import Q
|
||||
from django.db.models import Q, Prefetch
|
||||
from django.db import IntegrityError
|
||||
|
||||
from ..models import ProductCategory, ProductCategoryPhoto
|
||||
from ..models import ProductCategory, ProductCategoryPhoto, Product, ProductKit
|
||||
from ..forms import ProductCategoryForm
|
||||
from .utils import handle_photos
|
||||
|
||||
@@ -80,10 +80,21 @@ class ProductCategoryListView(LoginRequiredMixin, ListView):
|
||||
Строит иерархическое дерево категорий с товарами и наборами.
|
||||
Возвращает плоский список TreeItem объектов.
|
||||
"""
|
||||
# Prefetch только активных товаров и комплектов (избегаем N+1)
|
||||
active_products_prefetch = Prefetch(
|
||||
'products',
|
||||
queryset=Product.objects.filter(status='active').order_by('name')
|
||||
)
|
||||
active_kits_prefetch = Prefetch(
|
||||
'kits',
|
||||
queryset=ProductKit.objects.filter(status='active').order_by('name')
|
||||
)
|
||||
|
||||
# Получаем все категории из queryset с prefetch для товаров и наборов
|
||||
all_categories = list(queryset.select_related('parent')
|
||||
.prefetch_related('photos', 'children',
|
||||
'products', 'kits'))
|
||||
active_products_prefetch,
|
||||
active_kits_prefetch))
|
||||
|
||||
# Создаем словарь для быстрого доступа по ID
|
||||
categories_dict = {cat.pk: cat for cat in all_categories}
|
||||
@@ -111,15 +122,13 @@ class ProductCategoryListView(LoginRequiredMixin, ListView):
|
||||
tree_item = TreeItem(category, 'category', depth)
|
||||
result.append(tree_item)
|
||||
|
||||
# 2. Добавляем активные товары этой категории (отсортированные по имени)
|
||||
products = category.products.filter(status='active').order_by('name')
|
||||
for product in products:
|
||||
# 2. Добавляем активные товары этой категории (уже отфильтрованы и отсортированы через Prefetch)
|
||||
for product in category.products.all():
|
||||
product_item = TreeItem(product, 'product', depth + 1, category.pk)
|
||||
result.append(product_item)
|
||||
|
||||
# 3. Добавляем активные наборы этой категории (отсортированные по имени)
|
||||
kits = category.kits.filter(status='active').order_by('name')
|
||||
for kit in kits:
|
||||
# 3. Добавляем активные наборы этой категории (уже отфильтрованы и отсортированы через Prefetch)
|
||||
for kit in category.kits.all():
|
||||
kit_item = TreeItem(kit, 'kit', depth + 1, category.pk)
|
||||
result.append(kit_item)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user