category list filter created at field of products

in_stuck filter created at filter has discount filter
This commit is contained in:
Parsa Nazer
2025-01-14 22:02:58 +03:30
parent 7ae2cf9f4c
commit 59fa06c599
4 changed files with 103 additions and 17 deletions
@@ -0,0 +1,20 @@
# Generated by Django 5.1.2 on 2025-01-14 17:41
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('product', '0010_remove_productmodel_link_of_metas'),
]
operations = [
migrations.AddField(
model_name='productmodel',
name='created_at',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='زمان ثبت محصول'),
preserve_default=False,
),
]
@@ -0,0 +1,19 @@
# Generated by Django 5.1.2 on 2025-01-14 18:31
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('product', '0011_productmodel_created_at'),
]
operations = [
migrations.AddField(
model_name='productmodel',
name='category',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='product.categorymodel'),
),
]
+2 -1
View File
@@ -112,7 +112,8 @@ class ProductModel(models.Model):
meta_description = models.CharField(max_length=300, blank=True, null=True, help_text='این فیلد را حتما پر کنید')
meta_keywords = models.CharField(max_length=300, blank=True, null=True, help_text='این فیلد را حتما پر کنید')
meta_rating = models.FloatField(default=5, help_text='امتیاز محصول')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='زمان ثبت محصول')
category = models.ForeignKey(CategoryModel, blank=True, null=True, on_delete=models.SET_NULL)
def format_discount_price(self):
discount_price = int(self.price * (100 - self.discount) / 100)
formatted_num = "{:,.0f}".format(discount_price)
+62 -16
View File
@@ -12,6 +12,17 @@ from drf_spectacular.utils import extend_schema, OpenApiParameter
from drf_spectacular.types import OpenApiTypes
from rest_framework.permissions import AllowAny
# class CustomAPIView(APIView):
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# print('here')
# print(self.permission_classes)
# if not getattr(self, 'permission_classes')[0] != AllowAny or not self.permission_classes:
# print('asdf')
# self.authentication_classes = []
class AllCategories(APIView):
serializer_class = CategorySerializer
authentication_classes = []
@@ -29,10 +40,17 @@ class ProductView(APIView):
product_ser = self.serializer_class(instance=product, many=False)
return Response(product_ser.data, status=status.HTTP_200_OK)
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
from django.db.models import Q
class AllProductsView(APIView):
serializer_class = ProductSerializer
pagination_class = StructurePagination
authentication_classes = []
authentication_classes = [] # Add authentication if required
@extend_schema(
parameters=[
OpenApiParameter(
@@ -43,10 +61,12 @@ class AllProductsView(APIView):
),
OpenApiParameter(
name="category",
description="Filter by category ID.",
type={'type': 'array', 'items': {'type': 'number'}},
location=OpenApiParameter.QUERY,
required=False,
type=OpenApiTypes.INT,
),
style='form',
explode=False,
),
OpenApiParameter(
name="price_gte",
description="Filter products with price greater than or equal to this value.",
@@ -63,7 +83,7 @@ class AllProductsView(APIView):
name="sort",
description=(
"Sort results by one of the following fields:\n"
"`name`, `-name`, `price`, `-price`, `discount`, `-discount`."
"`name`, `-name`, `price`, `-price`, `discount`, `-discount`, `created_at`, `-created_at`."
"\nPrefix with `-` for descending order."
),
required=False,
@@ -81,32 +101,56 @@ class AllProductsView(APIView):
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 category ID to filter products in that category and its subcategories."
"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, pk=None):
def get(self, request):
try:
if pk:
category = Category.objects.get(pk=pk)
products = ProductModel.objects.filter(category__in=category.get_descendants(include_self=True))
# Get list of category IDs from query parameters
category_ids = request.query_params.getlist('category', [])
if category_ids:
# Convert category IDs to integers and filter products by these categories
category_ids = [int(id) for id in category_ids]
products = ProductModel.objects.filter(category__id__in=category_ids)
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))
category_filter = request.query_params.get('category', None)
if category_filter:
products = products.filter(category__id=category_filter)
# Price filters
price_gte = request.query_params.get('price_gte', None)
price_lte = request.query_params.get('price_lte', None)
if price_gte:
@@ -114,18 +158,20 @@ class AllProductsView(APIView):
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']:
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)
serializer = self.serializer_class(paginated_products, many=True)
return paginator.get_paginated_response(serializer.data)
except Category.DoesNotExist:
except CategoryModel.DoesNotExist:
return Response({"detail": "Category not found."}, status=status.HTTP_404_NOT_FOUND)