From 46df260813447428838d9ed9447e8caf382e6c2d Mon Sep 17 00:00:00 2001 From: mohsentaba Date: Sun, 21 Jun 2026 17:43:49 +0330 Subject: [PATCH] hadith filters on the category level added --- apps/hadis/views/hadis.py | 63 ++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/apps/hadis/views/hadis.py b/apps/hadis/views/hadis.py index 020d96d..f595fe4 100644 --- a/apps/hadis/views/hadis.py +++ b/apps/hadis/views/hadis.py @@ -11,6 +11,8 @@ from ..serializers.category import get_localized_text from ..models import Transmitters, HadisCategory, Hadis, HadisCollection,HadisTransmitter , HadisCorrection ,HadisReference, HadisStatus ,ReferenceImage from ..serializers import HadisListSerializer, HadisBasicSerializer, HadisDetailSerializer, HadisCollectionListSerializer, HadisSyncSerializer,HadisCorrectionSerializer,HadisTransmitterListSerializer , SimpleCategory, NarratorLayerSerializer , PinnedHadisCollectionSerializer from ..docs import arguments_filters_swagger ,hadis_list_swagger, hadis_detail_swagger, hadis_collections_swagger, hadis_sync_swagger, hadis_transmitters_swagger, hadis_corrections_swagger, hadis_basic_swagger, hadis_main_list_swagger, hadis_layers_swagger +from django.db.models import Q +from ..serializers.category import get_localized_text from rest_framework import status @@ -161,9 +163,6 @@ class HadisListView(ListAPIView): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) - def get(self, request, *args, **kwargs): - return self.list(request, *args, **kwargs) - def list(self, request, *args, **kwargs): # 1. Run the standard list logic (get pagination, filter, results) response = super().list(request, *args, **kwargs) @@ -175,18 +174,15 @@ class HadisListView(ListAPIView): # 3. Serialize this single category for the Hero section category_data = SimpleCategory(category_obj).data - # 👇 4. NEW LOGIC: Check if it's a Quran Category and fetch verse data + # 4. Check if it's a Quran Category and fetch verse data quran_data = None if category_obj.source_type == HadisCategory.SourceType.QURAN: - # سعی می‌کنیم آبجکت قرآن متصل به این کتگوری رو بگیریم try: - # استفاده از prefetch_related برای ترجمه‌های ثانویه جهت جلوگیری از N+1 from ..models.category import CategoryQuranVerse verse_obj = CategoryQuranVerse.objects.prefetch_related( 'secondary_translations' ).get(category=category_obj) - # سریالایز کردن دیتای قرآن (با کانتکست ریکوئست برای زبان) from ..serializers.category import CategoryQuranVerseSerializer quran_data = CategoryQuranVerseSerializer( verse_obj, @@ -195,7 +191,20 @@ class HadisListView(ListAPIView): except CategoryQuranVerse.DoesNotExist: pass - # 5. Inject it into the response data + # 👇 5. NEW LOGIC: Fetch all statuses for frontend filtering UI + lang = getattr(request, "LANGUAGE_CODE", None) or "fa" + statuses_list = [ + { + "id": status.id, + "slug": status.slug, + "title": get_localized_text(status.title, request=request, language_code=lang) or "", + "color": status.color, + "main_color_code": status.main_color_code, + } + for status in HadisStatus.objects.all().order_by('order') + ] + + # 6. Inject it into the response data if isinstance(response.data, dict): ordered_data = {} for key in ['count', 'next', 'previous']: @@ -203,10 +212,11 @@ class HadisListView(ListAPIView): ordered_data[key] = response.data[key] ordered_data['current_category'] = category_data - - # 👇 دیتای قرآن را تزریق می‌کنیم ordered_data['quran_data'] = quran_data + # 👇 تزریق لیست استاتوس‌ها قبل از نتایج + ordered_data['statuses'] = statuses_list + if 'results' in response.data: ordered_data['results'] = response.data['results'] response.data = ordered_data @@ -222,12 +232,36 @@ class HadisListView(ListAPIView): category__slug=category_slug, status=True ).annotate( - # distinct=True is CRITICAL here. - # Without it, if 3 narrators are from "Layer 1", it counts as 3. - # With it, it counts as 1 (unique layer). layer_count=Count('transmitters__narrator_layer', distinct=True) ).select_related('category') + # 👇 1. Apply Search Filter + search_query = self.request.query_params.get('search', None) + if search_query: + search_conditions = Q(text__icontains=search_query) + search_conditions |= Q(title__icontains=search_query) + search_conditions |= Q(title_narrator__icontains=search_query) + search_conditions |= Q(translation__icontains=search_query) + queryset = queryset.filter(search_conditions) + + # 👇 2. Apply Status Filter (Supports multiple comma-separated slugs) + status_filter = self.request.query_params.get('status', None) + if status_filter: + status_slugs = [s.strip() for s in status_filter.split(',')] + queryset = queryset.filter(hadis_status__slug__in=status_slugs) + + # 👇 3. Apply Transmitter Filter (Supports multiple comma-separated slugs) + transmitter_filter = self.request.query_params.get('transmitter', None) + if transmitter_filter: + transmitter_slugs = [t.strip() for t in transmitter_filter.split(',')] + queryset = queryset.filter(transmitters__transmitter__slug__in=transmitter_slugs) + + # 👇 4. Apply Source Filter (Supports multiple comma-separated slugs) + source_filter = self.request.query_params.get('source', None) + if source_filter: + source_slugs = [s.strip() for s in source_filter.split(',')] + queryset = queryset.filter(references__book_reference__slug__in=source_slugs) + # Filter by bookmarks if provided is_bookmark = self.request.query_params.get('is_bookmark', '').lower() if is_bookmark == 'true' and self.request.user.is_authenticated: @@ -239,7 +273,8 @@ class HadisListView(ListAPIView): ).values_list('content_id', flat=True) queryset = queryset.filter(id__in=bookmarked_ids) - return queryset + # ❗️ distinct() برای جلوگیری از دابلیکیت شدن احادیث به خاطر ManyToMany ها الزامی است + return queryset.distinct() def get_serializer_context(self): """Add user bookmarks to serializer context to avoid caching issues"""