From 245f31f5462a7b68cc32a27b25e624437ec47bd6 Mon Sep 17 00:00:00 2001 From: AmirHossein Shirazi Date: Fri, 13 Dec 2024 11:18:41 +0330 Subject: [PATCH] complete sorting of all products view --- backend/product/views.py | 94 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/backend/product/views.py b/backend/product/views.py index c7061a5..1d1fdfa 100644 --- a/backend/product/views.py +++ b/backend/product/views.py @@ -8,6 +8,9 @@ from django.db.models import Q from django.shortcuts import get_object_or_404 from rest_framework.permissions import IsAuthenticatedOrReadOnly from utils.pagination import StructurePagination +from drf_spectacular.utils import extend_schema, OpenApiParameter +from drf_spectacular.types import OpenApiTypes + class AllCategories(APIView): serializer_class = CategorySerializer @@ -26,14 +29,99 @@ class ProductView(APIView): class AllProductsView(APIView): serializer_class = ProductSerializer pagination_class = StructurePagination - def get(self, request, pk): + + @extend_schema( + parameters=[ + OpenApiParameter( + name="search", + description="Search by product name or description.", + required=False, + type=OpenApiTypes.STR, + ), + OpenApiParameter( + name="category", + description="Filter by category ID.", + required=False, + type=OpenApiTypes.INT, + ), + OpenApiParameter( + name="price_gte", + description="Filter products with price greater than or equal to this value.", + required=False, + type=OpenApiTypes.FLOAT, + ), + OpenApiParameter( + name="price_lte", + description="Filter products with price less than or equal to this value.", + required=False, + type=OpenApiTypes.FLOAT, + ), + OpenApiParameter( + name="sort", + description=( + "Sort results by one of the following fields:\n" + "`name`, `-name`, `price`, `-price`, `discount`, `-discount`." + "\nPrefix with `-` for descending order." + ), + required=False, + type=OpenApiTypes.STR, + ), + OpenApiParameter( + name="limit", + description="Number of results to return per page (pagination).", + required=False, + type=OpenApiTypes.INT, + ), + OpenApiParameter( + name="offset", + description="The starting position of the results (pagination).", + required=False, + type=OpenApiTypes.INT, + ), + ], + description=( + "Retrieve products with optional filters and sorting. " + "Provide a category ID to filter products in that category and its subcategories." + ), + responses={ + 200: ProductSerializer(many=True), + 404: OpenApiTypes.OBJECT, + }, + ) + def get(self, request, pk=None): try: - category = Category.objects.get(pk=pk) - products = Product.objects.filter(category__in=category.get_descendants(include_self=True)) + if pk: + category = Category.objects.get(pk=pk) + products = ProductModel.objects.filter(category__in=category.get_descendants(include_self=True)) + else: + products = ProductModel.objects.all() + + search_query = request.query_params.get('search', None) + if search_query: + products = products.filter(Q(name__icontains=search_query) | Q(description__icontains=search_query)) + + category_filter = request.query_params.get('category', None) + if category_filter: + products = products.filter(category__id=category_filter) + + price_gte = request.query_params.get('price_gte', None) + price_lte = request.query_params.get('price_lte', None) + if price_gte: + products = products.filter(price__gte=price_gte) + if price_lte: + products = products.filter(price__lte=price_lte) + + sort_by = request.query_params.get('sort', None) + if sort_by in ['name', '-name', 'price', '-price', 'discount', '-discount']: + products = products.order_by(sort_by) + else: + products = products.order_by('name') + paginator = self.pagination_class() paginated_products = paginator.paginate_queryset(products, request) serializer = self.serializer_class(paginated_products, many=True) return paginator.get_paginated_response(serializer.data) + except Category.DoesNotExist: return Response({"detail": "Category not found."}, status=status.HTTP_404_NOT_FOUND)