From 09a5c067d9c30ed52b162cae9150f538c2e07c73 Mon Sep 17 00:00:00 2001 From: mohsentaba Date: Thu, 9 Apr 2026 11:47:14 +0330 Subject: [PATCH] library sorting added --- apps/library/doc.py | 2 +- apps/library/views.py | 55 ++++++++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/apps/library/doc.py b/apps/library/doc.py index 0014b77..c08c521 100644 --- a/apps/library/doc.py +++ b/apps/library/doc.py @@ -52,7 +52,7 @@ category_param = openapi.Parameter( sort_param = openapi.Parameter( 'sort', openapi.IN_QUERY, - description="Sort books by field. Options: created_at, -created_at, view_count, -view_count, download_count, -download_count, title, -title, pin, -pin, -pin,-created_at", + description="Sort books by field. Options: most_popular, newest, most_view, most_rated, created_at, -created_at, view_count, -view_count, download_count, -download_count, title, -title, pin, -pin, -pin,-created_at", type=openapi.TYPE_STRING, required=False ) diff --git a/apps/library/views.py b/apps/library/views.py index 78878f7..c972e23 100644 --- a/apps/library/views.py +++ b/apps/library/views.py @@ -1,4 +1,4 @@ -from django.db.models import Count, Q +from django.db.models import Count, Q, Avg, OuterRef, Subquery, F from rest_framework.permissions import IsAuthenticated , AllowAny from rest_framework.authentication import TokenAuthentication from rest_framework.response import Response @@ -158,25 +158,48 @@ class BookListView(ListAPIView): # status=True # ).values_list('content_id', flat=True) - # Filter books by these IDs - queryset = queryset.filter(id__in=bookmarked_ids) + # Import Rate here to avoid circular imports if any + from apps.bookmark.models.rate import Rate + + # Subquery to calculate average rating for each book + avg_rating = Rate.objects.filter( + service=Rate.ServiceChoices.LIBRARY, + content_id=OuterRef('pk'), + status=True + ).order_by().values('content_id').annotate( + avg_rate=Avg('rate') + ).values('avg_rate') + + queryset = queryset.annotate(average_rate=Subquery(avg_rating)) + + # Sort mapping + sort_mapping = { + 'most_popular': [F('download_count').desc(nulls_last=True), '-created_at'], + 'newest': ['-created_at'], + 'most_view': [F('view_count').desc(nulls_last=True), '-created_at'], + 'most_rated': [F('average_rate').desc(nulls_last=True), '-created_at'], + } # Sort by parameter sort = self.request.query_params.get('sort', '-pin,-created_at') - # Allowed sort fields - allowed_sorts = [ - 'created_at', '-created_at', 'view_count', '-view_count', - 'download_count', '-download_count', 'title', '-title', - 'pin', '-pin', '-pin,-created_at' - ] - if sort in allowed_sorts: - # Handle multiple sort fields (e.g., '-pin,-created_at') - if ',' in sort: - queryset = queryset.order_by(*sort.split(',')) - else: - queryset = queryset.order_by(sort) + + if sort in sort_mapping: + queryset = queryset.order_by(*sort_mapping[sort]) else: - queryset = queryset.order_by('-pin', '-created_at') + # Allowed sort fields + allowed_sorts = [ + 'created_at', '-created_at', 'view_count', '-view_count', + 'download_count', '-download_count', 'title', '-title', + 'pin', '-pin', '-pin,-created_at' + ] + if sort in allowed_sorts: + # Handle multiple sort fields (e.g., '-pin,-created_at') + if ',' in sort: + queryset = queryset.order_by(*sort.split(',')) + else: + queryset = queryset.order_by(sort) + else: + queryset = queryset.order_by('-pin', '-created_at') return queryset