diff --git a/backend/product/models.py b/backend/product/models.py index 69b1034..6ee1562 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -1,6 +1,58 @@ from django.db import models from django.utils.text import slugify from django.contrib.auth.models import User +from django.urls import reverse + +class CategoryModel(models.Model): + name = models.CharField(max_length=50, verbose_name='نام دسته‌بندی') + slug = models.SlugField( + max_length=50, + unique=True, + help_text="اسم دسته را برای مسیر به انگلیسی و بدون فاصله وارد کنید" + ) + parent = models.ForeignKey( + 'self', + on_delete=models.CASCADE, + related_name='children', + null=True, + blank=True, + verbose_name='دسته‌بندی والد' + ) + icon = models.CharField(max_length=100, verbose_name='آیکون دسته‌بندی', blank=True, null=True) + meta_title = models.CharField( + max_length=60, + verbose_name="عنوان متا", + help_text="عنوان متا برای SEO", + blank=True, + null=True + ) + meta_description = models.TextField( + max_length=160, + verbose_name="توضیحات متا", + help_text="توضیحات متا برای SEO", + blank=True, + null=True + ) + + class Meta: + verbose_name = "دسته‌بندی" + verbose_name_plural = "دسته‌بندی‌ها" + ordering = ['parent__id', 'id'] # Optional: to order by hierarchy + + def __str__(self): + return self.name + + def get_absolute_url(self): + return reverse('category_detail', kwargs={'slug': self.slug}) + + def get_breadcrumb(self): + breadcrumb = [] + category = self + while category: + breadcrumb.append(category) + category = category.parent + return breadcrumb[::-1] + class ProductModel(models.Model): name = models.CharField(max_length=255) description = models.TextField() diff --git a/backend/product/serializers.py b/backend/product/serializers.py index 3852d8e..507eafb 100644 --- a/backend/product/serializers.py +++ b/backend/product/serializers.py @@ -1,9 +1,29 @@ from .models import * from rest_framework import serializers +class ProductSerializer(serializers.ModelSerializer): + class Meta: + model = ProductModel + fields = "__all__" + read_only_fields = "__all__" + class CommentSerializer(serializers.ModelSerializer): class Meta: model = CommentModel fields = "__all__" - read_only_fields = ('show', 'product') \ No newline at end of file + read_only_fields = ('show', 'product') + + +class CategorySerializer(serializers.ModelSerializer): + children = serializers.SerializerMethodField() + + class Meta: + model = Category + fields = ['id', 'name', 'slug', 'icon', 'meta_title', 'meta_description', 'parent', 'children'] + + def get_children(self, obj): + children = obj.children.all() + if children.exists(): + return CategorySerializer(children, many=True).data + return [] \ No newline at end of file diff --git a/backend/product/urls.py b/backend/product/urls.py new file mode 100644 index 0000000..8d77f11 --- /dev/null +++ b/backend/product/urls.py @@ -0,0 +1,10 @@ +from django.urls import path +from .views import AllCategories, ProductView, AllProductsView, CommentView + +urlpatterns = [ + path('categories/', AllCategories.as_view(), name='all-categories'), + path('products//', ProductView.as_view(), name='product-detail'), + path('categories//products/', AllProductsView.as_view(), name='category-products'), + path('products//comments/', CommentView.as_view(), name='product-comments'), + path('comments//', CommentView.as_view(), name='comment-delete'), +] \ No newline at end of file diff --git a/backend/product/views.py b/backend/product/views.py index 4a56668..01192b4 100644 --- a/backend/product/views.py +++ b/backend/product/views.py @@ -7,6 +7,35 @@ 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 + +class AllCategories(APIView): + serializer_class = CategorySerializer + def get(self, request): + categories = CategoryModel.objects.all() + categories_ser = self.serializer_class(instance=categories, many=True) + return Response({"categories": categories_ser.data}, status=status.HTTP_200_OK) + +class ProductView(APIView): + serializer_class = ProductModel + def get(self, request, pk): + product = get_object_or_404(ProductModel, id=pk) + product_ser = self.serializer_class(instance=product, many=False) + return Response({"product": product_ser.data}, status=status.HTTP_200_OK) + +class AllProductsView(APIView): + serializer_class = ProductSerializer + pagination_class = StructurePagination + def get(self, request, pk): + try: + category = Category.objects.get(pk=pk) + products = Product.objects.filter(category__in=category.get_descendants(include_self=True)) + 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) class CommentView(APIView):