diff --git a/myproject/products/views/api_views.py b/myproject/products/views/api_views.py index 656fb41..dd6b754 100644 --- a/myproject/products/views/api_views.py +++ b/myproject/products/views/api_views.py @@ -7,11 +7,30 @@ from django.core.cache import cache from django.core.exceptions import ValidationError import logging -from ..models import Product, ProductVariantGroup, ProductKit, ProductCategory +from ..models import Product, ProductVariantGroup, ProductKit, ProductCategory, ProductPhoto logger = logging.getLogger(__name__) +def _get_product_photo_url(product_id): + """Получает URL главного фото товара (первого по порядку).""" + photo = ProductPhoto.objects.filter(product_id=product_id).order_by('order').first() + if photo and photo.image: + return photo.image.url + return None + + +def _apply_product_filters(queryset, category_id=None, tag_id=None, in_stock_only=False): + """Применяет фильтры к queryset товаров.""" + if category_id: + queryset = queryset.filter(categories__id=category_id) + if tag_id: + queryset = queryset.filter(tags__id=tag_id) + if in_stock_only: + queryset = queryset.filter(in_stock=True) + return queryset.distinct() + + def search_products_and_variants(request): """ API endpoint для поиска товаров, групп вариантов и комплектов (совместимость с Select2). @@ -22,6 +41,9 @@ def search_products_and_variants(request): - id: ID товара/комплекта для получения его данных (формат: "product_123" или "kit_456") - type: 'product', 'variant', 'kit' или 'all' (опционально, по умолчанию 'all') - page: номер страницы для пагинации (по умолчанию 1) + - category: ID категории для фильтрации (опционально) + - tag: ID тега для фильтрации (опционально) + - in_stock: 'true' для фильтрации только товаров в наличии (опционально) Возвращает JSON в формате Select2 с группировкой: { @@ -130,24 +152,34 @@ def search_products_and_variants(request): page = int(request.GET.get('page', 1)) page_size = 30 + # Дополнительные фильтры + category_id = request.GET.get('category', '').strip() + tag_id = request.GET.get('tag', '').strip() + in_stock_only = request.GET.get('in_stock', '').lower() == 'true' + results = [] + # Проверяем, есть ли дополнительные фильтры + has_filters = category_id or tag_id or in_stock_only + # Если поиска нет - показываем популярные товары и комплекты if not query or len(query) < 2: - # Кэшируем популярные товары на 1 час - cache_key = f'popular_items_{search_type}' - cached_results = cache.get(cache_key) - - if cached_results: - return JsonResponse(cached_results) + # Кэшируем только если нет фильтров + if not has_filters: + cache_key = f'popular_items_{search_type}' + cached_results = cache.get(cache_key) + if cached_results: + return JsonResponse(cached_results) product_results = [] kit_results = [] if search_type in ['all', 'product']: # Показываем последние добавленные активные товары - products = Product.objects.filter(status='active')\ - .order_by('-created_at')[:page_size]\ + products_qs = Product.objects.filter(status='active') + # Применяем фильтры + products_qs = _apply_product_filters(products_qs, category_id, tag_id, in_stock_only) + products = products_qs.order_by('-created_at')[:page_size]\ .values('id', 'name', 'sku', 'price', 'sale_price', 'in_stock') for product in products: @@ -165,7 +197,8 @@ def search_products_and_variants(request): 'price': str(product['price']) if product['price'] else None, 'actual_price': str(actual_price) if actual_price else '0', 'in_stock': product['in_stock'], - 'type': 'product' + 'type': 'product', + 'photo_url': _get_product_photo_url(product['id']) }) if search_type in ['all', 'kit']: @@ -214,7 +247,9 @@ def search_products_and_variants(request): 'results': results, 'pagination': {'more': False} } - cache.set(cache_key, response_data, 3600) + # Кэшируем только если нет фильтров + if not has_filters: + cache.set(cache_key, response_data, 3600) return JsonResponse(response_data) # Поиск товаров и комплектов (регистронезависимый поиск с приоритетом точных совпадений) @@ -269,6 +304,9 @@ def search_products_and_variants(request): ) ).order_by('-relevance', 'name') + # Применяем дополнительные фильтры + products_query = _apply_product_filters(products_query, category_id, tag_id, in_stock_only) + total_products = products_query.count() start = (page - 1) * page_size end = start + page_size @@ -290,7 +328,8 @@ def search_products_and_variants(request): 'price': str(product['price']) if product['price'] else None, 'actual_price': str(actual_price) if actual_price else '0', 'in_stock': product['in_stock'], - 'type': 'product' + 'type': 'product', + 'photo_url': _get_product_photo_url(product['id']) }) has_more = total_products > end