This commit is contained in:
A'zamov Samandar
2025-12-06 21:50:28 +05:00
parent 3aa20fdaa1
commit f5766aa319
140 changed files with 2376 additions and 1582 deletions

View File

@@ -1,6 +1,10 @@
from .category import * # noqa
from .search import * # noqa
from .ad import * # noqa
from .user import * # noqa
from .notification import * # noqa
from .banner import * # noqa
from .ad import *
from .banner import *
from .category import *
from .common import * # noqa
from .feedback import *
from .notification import *
from .order import *
from .search import *
from .tags import *
from .user import *

View File

@@ -1,2 +1,2 @@
from .home_api import * # noqa
from .ad import * # noqa
from .home_api import *
from .ad import *

View File

@@ -1,43 +1,70 @@
from rest_framework.viewsets import ReadOnlyModelViewSet
from rest_framework.permissions import AllowAny
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter
from django_core.mixins import BaseViewSetMixin
from core.apps.api.models import AdModel
from django_filters.rest_framework import DjangoFilterBackend
from core.apps.api.filters import AdFilter
from core.apps.api.serializers.ad.ad import (
FullListAdSerializer,
RetrieveAdSerializer,
CreateAdSerializer,
AdListSerializer,
AdDetailSerializer,
AdCreateSerializer,
)
@extend_schema(tags=["Ads"])
class AdsView(BaseViewSetMixin, ReadOnlyModelViewSet):
queryset = AdModel.objects.all().order_by("-created_at")
serializer_class = FullListAdSerializer
@extend_schema_view(
list=extend_schema(
summary="List all ads",
description="Get paginated list of all available ads with filtering options",
tags=["Ads"],
parameters=[
OpenApiParameter(
name="category",
description="Filter by category ID",
required=False,
type=int
),
OpenApiParameter(
name="min_price",
description="Minimum price filter",
required=False,
type=float
),
OpenApiParameter(
name="max_price",
description="Maximum price filter",
required=False,
type=float
),
]
),
retrieve=extend_schema(
summary="Get ad details",
description="Get detailed information about a specific ad including images, variants, and options",
tags=["Ads"]
),
)
class AdViewSet(BaseViewSetMixin, ReadOnlyModelViewSet):
"""
ViewSet for viewing and managing ads.
list: Get list of all available ads with filtering
retrieve: Get detailed information about a specific ad
"""
queryset = AdModel.objects.select_related(
"category", "user", "plan"
).prefetch_related(
"images", "variants", "options", "tags"
).filter(is_available=True).order_by("-created_at")
serializer_class = AdListSerializer
permission_classes = [AllowAny]
filter_backends = [DjangoFilterBackend]
filterset_class = AdFilter
action_permission_classes = {}
action_serializer_class = {
"list": FullListAdSerializer,
"retrieve": RetrieveAdSerializer,
"create": CreateAdSerializer,
}
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
data = {"ads": page}
serializer = FullListAdSerializer(data, context={"request": request})
return self.get_paginated_response(serializer.data)
data = {"ads": queryset}
serializer = FullListAdSerializer(data, context={"request": request})
response = self.get_paginated_response(serializer.data)
return response
def get_serializer_class(self):
if self.action == "retrieve":
return AdDetailSerializer
elif self.action == "create":
return AdCreateSerializer
return AdListSerializer

View File

@@ -1,24 +1,30 @@
from rest_framework.viewsets import ReadOnlyModelViewSet
from rest_framework.permissions import AllowAny
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import extend_schema, extend_schema_view
from django_core.mixins import BaseViewSetMixin
from core.apps.api.models import AdModel
from core.apps.api.serializers.ad.home_api import (
ListHomeAdSerializer,
CreateHomeAdSerializer,
RetrieveHomeAdSerializer,
from core.apps.api.serializers.ad.home_api import HomeAdListSerializer
@extend_schema_view(
list=extend_schema(
summary="Get home page ads",
description="Get optimized list of ads for home page (latest 20 ads)",
tags=["Home"]
),
)
@extend_schema(tags=["Home Ad Api"])
class HomeAdApiView(BaseViewSetMixin, ReadOnlyModelViewSet):
queryset = AdModel.objects.all()
serializer_class = ListHomeAdSerializer
class HomeAdViewSet(BaseViewSetMixin, ReadOnlyModelViewSet):
"""
ViewSet for home page ads - optimized for performance
Returns latest 20 available ads without pagination
"""
queryset = AdModel.objects.select_related(
"category", "user"
).filter(
is_available=True
).order_by("-created_at")[:20]
serializer_class = HomeAdListSerializer
permission_classes = [AllowAny]
action_permission_classes = {}
action_serializer_class = {
"list": ListHomeAdSerializer,
"retrieve": RetrieveHomeAdSerializer,
"create": CreateHomeAdSerializer,
}
pagination_class = None # Disable pagination for home page

View File

@@ -1 +1 @@
from .banner import * # noqa
from .banner import *

View File

@@ -1,9 +1,9 @@
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.viewsets import ReadOnlyModelViewSet
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import extend_schema, extend_schema_view
from django_core.mixins import BaseViewSetMixin
from core.apps.api.models import Banner
from core.apps.api.models import BannerModel
from core.apps.api.serializers.banner import (
ListBannerSerializer,
RetrieveBannerSerializer,
@@ -11,15 +11,30 @@ from core.apps.api.serializers.banner import (
)
@extend_schema(tags=['Banner'])
@extend_schema_view(
list=extend_schema(
summary="List all active banners",
description="Get list of all active banners ordered by display order",
tags=["Banners"]
),
retrieve=extend_schema(
summary="Get banner details",
description="Get detailed information about a specific banner",
tags=["Banners"]
),
)
class BannerViewSet(BaseViewSetMixin, ReadOnlyModelViewSet):
queryset = Banner.objects.all()
"""
ViewSet for managing banners.
Returns active banners for display on website.
"""
queryset = BannerModel.objects.filter(is_active=True).order_by("order", "-created_at")
serializer_class = ListBannerSerializer
permission_classes = [AllowAny]
action_permission_classes = {}
action_serializers = {
'list': ListBannerSerializer,
'retrieve': RetrieveBannerSerializer,
'create': CreateBannerSerializer,
action_serializer_class = {
"list": ListBannerSerializer,
"retrieve": RetrieveBannerSerializer,
"create": CreateBannerSerializer,
}

View File

@@ -1 +1 @@
from .category import * # noqa
from .category import *

View File

@@ -1,8 +1,8 @@
from rest_framework.permissions import AllowAny
from rest_framework.viewsets import ReadOnlyModelViewSet
from django_core.mixins.base import BaseViewSetMixin
from drf_spectacular.utils import extend_schema
from core.apps.api.models import Category
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter
from core.apps.api.models import CategoryModel
from django_filters.rest_framework import DjangoFilterBackend
from core.apps.api.filters.category import CategoryFilter
from core.apps.api.serializers.category import (
@@ -13,16 +13,45 @@ from core.apps.api.serializers.category import (
)
@extend_schema(tags=["Category"])
@extend_schema_view(
list=extend_schema(
summary="List all categories",
description="Get hierarchical list of all root categories with their children",
tags=["Categories"],
parameters=[
OpenApiParameter(
name="show_home",
description="Filter categories shown on home page",
required=False,
type=bool
),
OpenApiParameter(
name="category_type",
description="Filter by category type (product/service)",
required=False,
type=str
),
]
),
retrieve=extend_schema(
summary="Get category details",
description="Get detailed information about a specific category",
tags=["Categories"]
),
)
class CategoryViewSet(BaseViewSetMixin, ReadOnlyModelViewSet):
queryset = Category.objects.filter(level=0)
"""
ViewSet for managing categories.
Returns hierarchical category structure.
"""
queryset = CategoryModel.objects.filter(level=0)
permission_classes = [AllowAny]
serializer_class = ListCategorySerializer
pagination_class = None
filter_backends = [DjangoFilterBackend]
filterset_class = CategoryFilter
action_permission_classes = {}
action_serializer_class = {
"list": ListCategorySerializer,
"retrieve": RetrieveCategorySerializer,
@@ -30,16 +59,26 @@ class CategoryViewSet(BaseViewSetMixin, ReadOnlyModelViewSet):
}
@extend_schema(tags=["Category"])
@extend_schema_view(
list=extend_schema(
summary="Get home page categories",
description="Get flat list of all categories for home page display",
tags=["Categories"]
),
)
class CategoryHomeApiViewSet(BaseViewSetMixin, ReadOnlyModelViewSet):
queryset = Category.objects.all()
"""
ViewSet for home page categories.
Returns flat list without hierarchy.
"""
queryset = CategoryModel.objects.all()
permission_classes = [AllowAny]
serializer_class = ListCategoryNoChildSerializer
pagination_class = None
filter_backends = [DjangoFilterBackend]
filterset_class = CategoryFilter
action_permission_classes = {}
action_serializer_class = {
"list": ListCategoryNoChildSerializer,
"retrieve": RetrieveCategorySerializer,

View File

@@ -0,0 +1,42 @@
from django_core.mixins import BaseViewSetMixin
from drf_spectacular.utils import extend_schema
from rest_framework.permissions import AllowAny
from rest_framework.viewsets import ReadOnlyModelViewSet
from core.apps.api.models import ColorModel, SizeModel
from core.apps.api.serializers.common import (
CreateColorSerializer,
CreateSizeSerializer,
ListColorSerializer,
ListSizeSerializer,
RetrieveColorSerializer,
RetrieveSizeSerializer,
)
@extend_schema(tags=["color"])
class ColorView(BaseViewSetMixin, ReadOnlyModelViewSet):
queryset = ColorModel.objects.all()
serializer_class = ListColorSerializer
permission_classes = [AllowAny]
action_permission_classes = {}
action_serializer_class = {
"list": ListColorSerializer,
"retrieve": RetrieveColorSerializer,
"create": CreateColorSerializer,
}
@extend_schema(tags=["size"])
class SizeView(BaseViewSetMixin, ReadOnlyModelViewSet):
queryset = SizeModel.objects.all()
serializer_class = ListSizeSerializer
permission_classes = [AllowAny]
action_permission_classes = {}
action_serializer_class = {
"list": ListSizeSerializer,
"retrieve": RetrieveSizeSerializer,
"create": CreateSizeSerializer,
}

View File

@@ -0,0 +1 @@
from .feedback import *

View File

@@ -0,0 +1,95 @@
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticatedOrReadOnly, IsAuthenticated
from rest_framework.decorators import action
from rest_framework.response import Response
from drf_spectacular.utils import extend_schema, extend_schema_view
from django_core.mixins import BaseViewSetMixin
from core.apps.api.models import FeedbackModel
from core.apps.api.serializers.feedback import (
FeedbackListSerializer,
FeedbackDetailSerializer,
FeedbackCreateSerializer,
FeedbackUpdateSerializer,
)
@extend_schema_view(
list=extend_schema(
summary="List all feedbacks", description="Get list of all product feedbacks/reviews", tags=["Feedbacks"]
),
retrieve=extend_schema(
summary="Get feedback details",
description="Get detailed information about a specific feedback",
tags=["Feedbacks"],
),
create=extend_schema(
summary="Create feedback", description="Create a new feedback/review for a product", tags=["Feedbacks"]
),
update=extend_schema(summary="Update feedback", description="Update your own feedback", tags=["Feedbacks"]),
partial_update=extend_schema(
summary="Partially update feedback", description="Partially update your own feedback", tags=["Feedbacks"]
),
destroy=extend_schema(summary="Delete feedback", description="Delete your own feedback", tags=["Feedbacks"]),
)
class FeedbackViewSet(BaseViewSetMixin, ModelViewSet):
"""
ViewSet for managing product feedbacks/reviews.
Users can create, read, update and delete their own feedbacks.
"""
queryset = FeedbackModel.objects.select_related("user", "ad").prefetch_related("images").order_by("-created_at")
permission_classes = [IsAuthenticatedOrReadOnly]
def get_queryset(self):
queryset = super().get_queryset()
ad_id = self.request.query_params.get("ad")
if ad_id:
queryset = queryset.filter(ad_id=ad_id)
user_id = self.request.query_params.get("user")
if user_id:
queryset = queryset.filter(user_id=user_id)
star = self.request.query_params.get("star")
if star:
queryset = queryset.filter(star=star)
return queryset
def get_serializer_class(self):
if self.action == "create":
return FeedbackCreateSerializer
elif self.action in ["update", "partial_update"]:
return FeedbackUpdateSerializer
elif self.action == "retrieve":
return FeedbackDetailSerializer
return FeedbackListSerializer
def perform_create(self, serializer):
serializer.save(user=self.request.user)
def perform_update(self, serializer):
if serializer.instance.user != self.request.user:
raise PermissionError("You can only update your own feedback")
serializer.save()
def perform_destroy(self, instance):
# Only allow users to delete their own feedback
if instance.user != self.request.user:
raise PermissionError("You can only delete your own feedback")
instance.delete()
@extend_schema(
summary="Get my feedbacks", description="Get all feedbacks created by the current user", tags=["Feedbacks"]
)
@action(detail=False, methods=["get"], permission_classes=[IsAuthenticated])
def my_feedbacks(self, request):
"""Get current user's feedbacks"""
queryset = self.get_queryset().filter(user=request.user)
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

View File

@@ -1 +1 @@
from .notification import * # noqa
from .notification import *

View File

@@ -24,7 +24,6 @@ class NotificationViewSet(BaseViewSetMixin, ReadOnlyModelViewSet):
serializer_class = ListUserNotificationSerializer
filter_backends = [DjangoFilterBackend]
action_permission_classes = {}
action_serializer_class = {
"list": ListUserNotificationSerializer,
"retrieve": RetrieveUserNotificationSerializer,

View File

@@ -0,0 +1 @@
from .order import *

View File

@@ -0,0 +1,88 @@
# type: ignore
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated
from rest_framework.decorators import action
from rest_framework.response import Response
from drf_spectacular.utils import extend_schema, extend_schema_view
from django_core.mixins import BaseViewSetMixin
from core.apps.api.models import OrderModel
from core.apps.api.serializers.order import (
OrderListSerializer,
OrderDetailSerializer,
OrderCreateSerializer,
OrderUpdateSerializer,
)
@extend_schema_view(
list=extend_schema(
summary="List all orders", description="Get list of all orders for the current user", tags=["Orders"]
),
retrieve=extend_schema(
summary="Get order details", description="Get detailed information about a specific order", tags=["Orders"]
),
create=extend_schema(summary="Create order", description="Create a new order with items", tags=["Orders"]),
update=extend_schema(summary="Update order", description="Update order status or address", tags=["Orders"]),
partial_update=extend_schema(
summary="Partially update order", description="Partially update order information", tags=["Orders"]
),
destroy=extend_schema(summary="Cancel order", description="Cancel/delete an order", tags=["Orders"]),
)
class OrderViewSet(BaseViewSetMixin, ModelViewSet):
"""
ViewSet for managing orders.
Users can only see and manage their own orders.
"""
permission_classes = [IsAuthenticated]
def get_queryset(self):
queryset = (
OrderModel.objects.select_related("user", "address")
.prefetch_related("items__ad")
.filter(user=self.request.user)
.order_by("-created_at")
)
# Filter by status
status_filter = self.request.query_params.get("status")
if status_filter:
queryset = queryset.filter(status=status_filter)
return queryset
def get_serializer_class(self):
if self.action == "create":
return OrderCreateSerializer
elif self.action in ["update", "partial_update"]:
return OrderUpdateSerializer
elif self.action == "retrieve":
return OrderDetailSerializer
return OrderListSerializer
def perform_create(self, serializer):
serializer.save(user=self.request.user)
def perform_destroy(self, instance):
# Only allow cancellation of pending orders
if instance.status not in ["pending", "processing"]:
raise PermissionError("Can only cancel pending or processing orders")
instance.delete()
@extend_schema(summary="Get order statistics", description="Get statistics about user's orders", tags=["Orders"])
@action(detail=False, methods=["get"])
def statistics(self, request):
"""Get order statistics for current user"""
queryset = self.get_queryset()
stats = {
"total_orders": queryset.count(),
"pending": queryset.filter(status="pending").count(),
"processing": queryset.filter(status="processing").count(),
"completed": queryset.filter(status="completed").count(),
"cancelled": queryset.filter(status="cancelled").count(),
"total_spent": sum(order.total_amount for order in queryset),
}
return Response(stats)

View File

@@ -1,2 +1,2 @@
from .search import * # noqa
from .search_ads import * # noqa
from .history import *
from .ad import *

View File

@@ -21,7 +21,6 @@ class SearchAdsViewSet(BaseViewSetMixin, mixins.ListModelMixin, GenericViewSet):
filter_backends = [DjangoFilterBackend, SearchFilter]
search_fields = ["name"]
action_permission_classes = {}
action_serializer_class = {
'list': ListSearchAdsSerializer,
}

View File

@@ -18,7 +18,7 @@ class SearchHistoryViewSet(BaseViewSetMixin, mixins.ListModelMixin, mixins.Creat
serializer_class = ListSearchHistorySerializer
permission_classes = [IsAuthenticated]
http_method_names = ['get', 'post', 'delete']
action_permission_classes = {}
action_serializer_class = {
'list': ListSearchHistorySerializer,
'create': CreateSearchHistorySerializer,

View File

@@ -0,0 +1 @@
from .tags import *

View File

@@ -0,0 +1,30 @@
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.filters import SearchFilter
from drf_spectacular.utils import extend_schema, extend_schema_view
from django_core.mixins import BaseViewSetMixin
from core.apps.api.models import TagsModel, ColorModel
from core.apps.api.serializers.tags import TagSerializer, ColorSerializer
@extend_schema_view(
list=extend_schema(summary="List all tags", description="Get list of all available tags", tags=["Tags"]),
retrieve=extend_schema(
summary="Get tag details", description="Get detailed information about a specific tag", tags=["Tags"]
),
create=extend_schema(summary="Create tag", description="Create a new tag (Admin only)", tags=["Tags"]),
update=extend_schema(summary="Update tag", description="Update tag information (Admin only)", tags=["Tags"]),
destroy=extend_schema(summary="Delete tag", description="Delete a tag (Admin only)", tags=["Tags"]),
)
class TagViewSet(BaseViewSetMixin, ModelViewSet):
"""
ViewSet for managing tags.
Everyone can read, only authenticated users can create/modify.
"""
queryset = TagsModel.objects.all().order_by("name")
serializer_class = TagSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
filter_backends = [SearchFilter]
search_fields = ["name", "slug"]

View File

@@ -1 +1 @@
from .ad_like import * # noqa
from .like import *

View File

@@ -1,28 +0,0 @@
from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
from django_core.mixins.base import BaseViewSetMixin
from drf_spectacular.utils import extend_schema
from rest_framework.permissions import IsAuthenticated
from core.apps.accounts.models import UserLike
from core.apps.api.serializers.user.ad_like import (
ListUserLikeSerializer,
CreateUserLikeSerializer,
)
@extend_schema(tags=['User Like'])
class UserLikeViewSet(BaseViewSetMixin, mixins.ListModelMixin, mixins.CreateModelMixin,
mixins.DestroyModelMixin, GenericViewSet):
serializer_class = ListUserLikeSerializer
permission_classes = [IsAuthenticated]
http_method_names = ['get', 'post', 'delete']
action_permission_classes = {}
action_serializer_class = {
'list': ListUserLikeSerializer,
'create': CreateUserLikeSerializer,
}
def get_queryset(self):
queryset = UserLike.objects.filter(user=self.request.user).order_by('-id')
return queryset

View File

@@ -0,0 +1,40 @@
from rest_framework import mixins
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from django_core.mixins.base import BaseViewSetMixin
from drf_spectacular.utils import extend_schema
from rest_framework.permissions import IsAuthenticated
from core.apps.accounts.models import UserLike
from core.apps.api.serializers.user.like import (
ListUserLikeSerializer,
CreateUserLikeSerializer,
)
@extend_schema(tags=["User Like"])
class UserLikeViewSet(BaseViewSetMixin, mixins.ListModelMixin, GenericViewSet):
serializer_class = ListUserLikeSerializer
permission_classes = [IsAuthenticated]
http_method_names = ["get", "post", "delete"]
action_serializer_class = {
"list": ListUserLikeSerializer,
"create": CreateUserLikeSerializer,
}
def create(self, request):
ser = self.get_serializer(data=request.data)
ser.is_valid(raise_exception=True)
instance = UserLike.objects.filter(user=request.user, ad=ser.validated_data.get("ad")).first()
if instance is not None:
instance.delete()
return Response(data={"detail": "deleted"})
self.perform_create(ser)
return Response(data={"detail": "created"})
def get_queryset(self):
queryset = UserLike.objects.filter(user=self.request.user).order_by("-id")
return queryset
def perform_create(self, serializer):
serializer.save(user=self.request.user)