from django.core.paginator import Paginator from rest_framework.views import APIView from .models import * from .serializers import * from rest_framework import status from rest_framework.response import Response 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, OpenApiTypes from rest_framework.permissions import AllowAny # class APIView(APIView): # def __init__(self, *args, **kwargs): # super().__init__(*args, **kwargs) # print('here') # print(self.permission_classes) # if AllowAny in self.permission_classes or not self.permission_classes: # print('asdf') # self.authentication_classes = [] class AllCategories(APIView): serializer_class = MainCategorySerializer @extend_schema( # parameters=[ # OpenApiParameter( # name="search", # description="Search by category name or description.", # required=False, # type=OpenApiTypes.STR, # ) # ], responses={ 200: MainCategorySerializer(many=True), 404: OpenApiTypes.OBJECT, }, ) def get(self, request): # search_query = request.query_params.get('search', None) # if search_query: # categories = MainCategoryModel.objects.filter(Q(name__icontains=search_query) | Q(slug__icontains=search_query)) # else: categories = MainCategoryModel.objects.all() categories_ser = self.serializer_class(instance=categories, many=True, context={'request': request}) return Response(categories_ser.data, status=status.HTTP_200_OK) class ProductView(APIView): serializer_class = ProductSerializer permission_classes = [AllowAny] def get(self, request, pk): product = get_object_or_404(ProductModel, id=pk) dollor_object, _ = DollorModel.objects.get_or_create(unique_filed='unique') dollor_price = dollor_object.price product_ser = self.serializer_class(instance=product, many=False, context={'dollor_price': dollor_price, 'request': request}) return Response(product_ser.data, status=status.HTTP_200_OK) class AllProductsView(APIView): serializer_class = ProductSerializer pagination_class = StructurePagination @extend_schema( parameters=[ OpenApiParameter( name="search", description="Search by product name or description.", required=False, type=OpenApiTypes.STR, ), # OpenApiParameter( # name="category", # type={'type': 'array', 'items': {'type': 'number'}}, # location=OpenApiParameter.QUERY, # required=False, # style='form', # explode=False, # ), OpenApiParameter( name="category", type=OpenApiTypes.INT, required=False, ), 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`, `created_at`, `-created_at`." "\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, ), OpenApiParameter( name="in_stock", description="Filter products that are in stock (positive stock).", required=False, type=OpenApiTypes.BOOL, ), OpenApiParameter( name="has_discount", description="Filter products that have a discount.", required=False, type=OpenApiTypes.BOOL, ) ], description=( "Retrieve products with optional filters and sorting. " "Provide a list of category IDs to filter products by those categories and their subcategories." ), responses={ 200: ProductSerializer(many=True), 404: OpenApiTypes.OBJECT, }, ) def get(self, request): try: category_id = request.query_params.get('category', None) if category_id: try: category_id = int(category_id) except ValueError: return Response({'detail': 'value error category id should be a number'}, status=status.HTTP_400_BAD_REQUEST) sub_category = get_object_or_404(SubCategoryModel, pk=category_id) products = ProductModel.objects.filter(category=sub_category) else: products = ProductModel.objects.all() # Filter by stock status if `in_stock` is specified in_stock = request.query_params.get('in_stock', "false") == 'true' if in_stock: products = products.filter(in_stock__gt=0) # Filter by discount if `has_discount` is specified has_discount = request.query_params.get('has_discount', "false") == 'true' if has_discount: products = products.filter(discount__gt=0) # Search filter search_query = request.query_params.get('search', None) if search_query: products = products.filter(Q(name__icontains=search_query) | Q(description__icontains=search_query)) # Price filters price_gte = request.query_params.get('price_gte', None) price_lte = request.query_params.get('price_lte', None) if type(price_gte) != int or type(price_lte) != int: return Response({'detail': 'value error price_gte and price_lte should be a number'}, status=status.HTTP_400_BAD_REQUEST) if price_gte: products = products.filter(price__gte=price_gte) if price_lte: products = products.filter(price__lte=price_lte) # Sorting sort_by = request.query_params.get('sort', None) if sort_by in ['name', '-name', 'price', '-price', 'discount', '-discount', 'created_at', '-created_at']: products = products.order_by(sort_by) else: products = products.order_by('name') # Pagination paginator = self.pagination_class() paginated_products = paginator.paginate_queryset(products, request) dollor_object, _ = DollorModel.objects.get_or_create(unique_filed='unique') dollor_price = dollor_object.price serializer = self.serializer_class(paginated_products, many=True, context={'dollor_price': dollor_price, 'request': request}) return paginator.get_paginated_response(serializer.data) except MainCategoryModel.DoesNotExist: return Response({"detail": "Category not found."}, status=status.HTTP_404_NOT_FOUND) class CommentView(APIView): serializer_class = CommentSerializer permission_classes = [IsAuthenticatedOrReadOnly] pagination_class = StructurePagination @extend_schema( parameters=[ 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, ) ], responses={ 200: CommentSerializer(many=True), 404: OpenApiTypes.OBJECT, }, ) def get(self, request, pk): product = get_object_or_404(ProductModel, id=pk) comments = product.comments.filter(show=True) paginator = self.pagination_class() paginated_comments = paginator.paginate_queryset(comments, request) comments_ser = self.serializer_class(instance=paginated_comments, many=True) return paginator.get_paginated_response(comments_ser.data) def post(self, request, pk): comment_ser = CommentSerializer(data=request.data) product = get_object_or_404(ProductModel, id=pk) if comment_ser.is_valid(): comment_ser.save(product=product, user=request.user) return Response(comment_ser.data, status=status.HTTP_201_CREATED) return Response(comment_ser.errors, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, pk): comment = get_object_or_404(CommentModel, pk=pk) if comment.user == request.user: comment.delete() return Response(status=status.HTTP_204_NO_CONTENT) else: return Response({"detail": "شما اجازه ی پاک کردن این کامنت را ندارید"}, status=status.HTTP_403_FORBIDDEN)