You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
758 lines
29 KiB
758 lines
29 KiB
from rest_framework.authentication import TokenAuthentication
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.generics import ListAPIView, RetrieveAPIView
|
|
from django.shortcuts import get_object_or_404
|
|
from utils.pagination import NoPagination, StandardResultsSetPagination
|
|
from rest_framework.pagination import PageNumberPagination
|
|
from rest_framework.response import Response
|
|
from django.db.models import Count
|
|
from django.db.models import Prefetch
|
|
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 rest_framework import status
|
|
|
|
class PinnedHadisCollectionListView(ListAPIView):
|
|
"""
|
|
API view to list pinned hadis collections with metadata info
|
|
"""
|
|
serializer_class = PinnedHadisCollectionSerializer
|
|
pagination_class = NoPagination
|
|
permission_classes = [IsAuthenticated]
|
|
authentication_classes = [TokenAuthentication]
|
|
|
|
@hadis_collections_swagger
|
|
def get(self, request, *args, **kwargs):
|
|
return self.list(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
return HadisCollection.objects.filter(
|
|
status=True,
|
|
pin_top=True
|
|
).order_by('order', '-created_at')
|
|
|
|
def list(self, request, *args, **kwargs):
|
|
# 1. گرفتن خروجی استاندارد لیست مجموعهها
|
|
response = super().list(request, *args, **kwargs)
|
|
|
|
# 2. محاسبه آمار (Info)
|
|
# تعداد کتگوریهای فعال
|
|
categories_count = HadisCategory.objects.count()
|
|
|
|
# تعداد نریتورها (راویان)
|
|
narrators_count = Transmitters.objects.count()
|
|
|
|
# تعداد سورسها (کتابهای منبع)
|
|
# فرض بر این است که BookReference مدل منابع شماست
|
|
from apps.hadis.models import BookReference
|
|
sources_count = BookReference.objects.count()
|
|
|
|
# تعداد بوکمارکهای کاربر در سرویس حدیث
|
|
from apps.bookmark.models.bookmark import Bookmark
|
|
bookmarks_count = Bookmark.objects.filter(
|
|
user=request.user,
|
|
service=Bookmark.ServiceChoices.HADITH,
|
|
status=True
|
|
).count()
|
|
|
|
# 3. ساختن دیکشنری info
|
|
info = {
|
|
"categories_count": categories_count,
|
|
# "bookmarks_count": bookmarks_count,
|
|
"narrators_count": narrators_count,
|
|
"sources_count": sources_count,
|
|
}
|
|
|
|
# 4. بازسازی دیتای نهایی مشابه اپ ویدیو
|
|
custom_data = {
|
|
"count": len(response.data) if isinstance(response.data, list) else response.data.get("count"),
|
|
"next": response.data.get("next") if isinstance(response.data, dict) else None,
|
|
"previous": response.data.get("previous") if isinstance(response.data, dict) else None,
|
|
"info": info,
|
|
"results": response.data if isinstance(response.data, list) else response.data.get("results")
|
|
}
|
|
|
|
return Response(custom_data, status=status.HTTP_200_OK)
|
|
|
|
|
|
class HadisCollectionListView(ListAPIView):
|
|
"""
|
|
API view to list all hadis collections
|
|
"""
|
|
queryset = HadisCollection.objects.filter(status=True).order_by('order')
|
|
serializer_class = HadisCollectionListSerializer
|
|
pagination_class = NoPagination
|
|
|
|
@hadis_collections_swagger
|
|
def get(self, request, *args, **kwargs):
|
|
return self.list(request, *args, **kwargs)
|
|
|
|
|
|
class HadisSyncView(ListAPIView):
|
|
"""
|
|
API view to sync all hadis data for offline mode
|
|
"""
|
|
serializer_class = HadisSyncSerializer
|
|
pagination_class = NoPagination
|
|
|
|
def get_queryset(self):
|
|
return (
|
|
Hadis.objects
|
|
.filter(status=True)
|
|
.select_related('category', 'hadis_status')
|
|
.prefetch_related(
|
|
'tags',
|
|
# 1. OPTIMIZED TRANSMITTERS
|
|
Prefetch(
|
|
'transmitters',
|
|
queryset=HadisTransmitter.objects.select_related(
|
|
'transmitter',
|
|
'transmitter__reliability', # <--- Fixes N+1 for reliability text
|
|
'narrator_layer'
|
|
).order_by('order')
|
|
),
|
|
# 2. OPTIMIZED REFERENCES
|
|
Prefetch(
|
|
'references',
|
|
queryset=HadisReference.objects
|
|
.select_related('book_reference')
|
|
.prefetch_related(
|
|
'book_reference__authors',
|
|
# <--- Fixes N+1 for Image ordering
|
|
Prefetch(
|
|
'images',
|
|
queryset=ReferenceImage.objects.order_by('priority')
|
|
)
|
|
)
|
|
),
|
|
'hadiscorrection_set',
|
|
)
|
|
.order_by('id')
|
|
)
|
|
|
|
@hadis_sync_swagger
|
|
def get(self, request, *args, **kwargs):
|
|
return self.list(request, *args, **kwargs)
|
|
|
|
def list(self, request, *args, **kwargs):
|
|
from django.utils.translation import get_language
|
|
|
|
# 1. PRE-FETCH DATA ONCE
|
|
queryset = self.get_queryset()
|
|
|
|
# Get language once for the entire bulk operation
|
|
lang = getattr(request, "LANGUAGE_CODE", None) or get_language() or "en"
|
|
|
|
# Pre-calculate base URL for images
|
|
media_url = request.build_absolute_uri('/')[:-1] # Remove trailing slash
|
|
|
|
results = []
|
|
for obj in queryset:
|
|
# --- Detail Block ---
|
|
status_block = None
|
|
if obj.hadis_status:
|
|
status_block = {
|
|
'id': obj.hadis_status.id,
|
|
'title': get_localized_text(obj.hadis_status.title, language_code=lang),
|
|
'color': obj.hadis_status.color,
|
|
'main_color_code': obj.hadis_status.main_color_code,
|
|
}
|
|
|
|
tags_block = [
|
|
{'id': tag.id, 'title': get_localized_text(tag.title, language_code=lang)}
|
|
for tag in obj.tags.all()
|
|
]
|
|
|
|
references_block = []
|
|
reference_images_block = []
|
|
for ref in obj.references.all():
|
|
book = ref.book_reference
|
|
references_block.append({
|
|
'id': ref.id,
|
|
'title': get_localized_text(book.title, language_code=lang) if book else None,
|
|
'authors': [
|
|
{'id': a.id, 'name': get_localized_text(a.name, language_code=lang)}
|
|
for a in (book.authors.all() if book else [])
|
|
],
|
|
'description': book.description if book else None,
|
|
})
|
|
|
|
for img in ref.images.all():
|
|
reference_images_block.append({
|
|
'id': img.id,
|
|
'thumbnail': f"{media_url}{img.thumbnail.url}" if img.thumbnail else None,
|
|
'priority': img.priority,
|
|
})
|
|
|
|
address_details_list = []
|
|
if hasattr(obj, 'address_details') and obj.address_details and isinstance(obj.address_details, list):
|
|
address_details_list = sorted(obj.address_details, key=lambda x: x.get('priority', 0))
|
|
|
|
detail_block = {
|
|
'address': get_localized_text(obj.address, language_code=lang),
|
|
'address_details': address_details_list,
|
|
'hadis_status': status_block,
|
|
'status_text': get_localized_text(obj.hadis_status_text, language_code=lang),
|
|
'share_link': obj.share_link,
|
|
'links': obj.links,
|
|
'tags': tags_block,
|
|
'references': references_block,
|
|
'reference_images': reference_images_block,
|
|
}
|
|
|
|
# --- Narrators Block ---
|
|
transmitters_data = []
|
|
for tr_rel in obj.transmitters.all():
|
|
t = tr_rel.transmitter
|
|
layer = tr_rel.narrator_layer
|
|
|
|
rel_data = None
|
|
if t.reliability:
|
|
rel_data = {
|
|
'id': t.reliability.id,
|
|
'title': get_localized_text(t.reliability.title, language_code=lang),
|
|
'color': t.reliability.color,
|
|
'main_color_code': t.reliability.main_color_code,
|
|
}
|
|
|
|
transmitters_data.append({
|
|
'id': t.id,
|
|
'name': get_localized_text(t.full_name, language_code=lang),
|
|
'slug': t.slug,
|
|
'known_as': get_localized_text(t.known_as, language_code=lang),
|
|
'nickname': get_localized_text(t.nickname, language_code=lang),
|
|
'reliability': rel_data,
|
|
'layer_level': layer.number if layer else None,
|
|
'layer_name': get_localized_text(layer.name, language_code=lang) if layer else None,
|
|
'is_gap': tr_rel.is_gap,
|
|
'birth_year_hijri': t.birth_year_hijri,
|
|
'death_year_hijri': t.death_year_hijri,
|
|
'order': tr_rel.order,
|
|
})
|
|
|
|
narrators_block = {
|
|
'description': get_localized_text(obj.description, language_code=lang),
|
|
'transmitters': transmitters_data,
|
|
}
|
|
|
|
# --- Explanations (Complex Logic) ---
|
|
explanation_data = []
|
|
if hasattr(obj, 'explanations') and obj.explanations and isinstance(obj.explanations, list):
|
|
for item in obj.explanations:
|
|
if isinstance(item, dict) and item.get('language_code') == lang:
|
|
explanation_data.append({
|
|
'title': item.get('title', ''),
|
|
'description': item.get('description', '')
|
|
})
|
|
|
|
if not explanation_data and obj.explanation:
|
|
explanation_data = get_localized_text(obj.explanation, language_code=lang)
|
|
else:
|
|
explanation_data = explanation_data if explanation_data else None
|
|
|
|
# --- Corrections ---
|
|
corrections_block = []
|
|
for c in obj.hadiscorrection_set.all():
|
|
corrections_block.append({
|
|
'id': c.id,
|
|
'title': get_localized_text(c.title, language_code=lang),
|
|
'description': get_localized_text(c.description, language_code=lang),
|
|
'translation': get_localized_text(c.translation, language_code=lang),
|
|
'share_link': c.share_link,
|
|
})
|
|
|
|
# --- Assemble Hadis Item ---
|
|
results.append({
|
|
'id': obj.id,
|
|
'number': obj.number,
|
|
'slug': obj.slug,
|
|
'category_id': obj.category_id,
|
|
'title': get_localized_text(obj.title, language_code=lang),
|
|
'title_narrator': get_localized_text(obj.title_narrator, language_code=lang),
|
|
'text': obj.text, # Usually JSON structure in our app
|
|
'translation': get_localized_text(obj.translation, language_code=lang),
|
|
'detail': detail_block,
|
|
'narrators': narrators_block,
|
|
'explanations': explanation_data,
|
|
'corrections': corrections_block,
|
|
})
|
|
|
|
return Response({
|
|
'count': len(results),
|
|
'results': results
|
|
})
|
|
|
|
|
|
class HadisListView(ListAPIView):
|
|
"""
|
|
API view to list Hadis by category_id
|
|
"""
|
|
serializer_class = HadisListSerializer
|
|
pagination_class = StandardResultsSetPagination
|
|
authentication_classes = [TokenAuthentication]
|
|
|
|
@hadis_list_swagger
|
|
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)
|
|
|
|
# 2. Find the "Parent" Category based on the URL slug
|
|
category_slug = self.kwargs.get('category_slug')
|
|
category_obj = get_object_or_404(HadisCategory, slug=category_slug)
|
|
|
|
# 3. Serialize this single category for the Hero section
|
|
# You might need a simple serializer just for titles/descriptions
|
|
category_data = SimpleCategory(category_obj).data
|
|
|
|
# 4. Inject it into the response data
|
|
# Note: We access response.data because we are using DRF's Response object
|
|
if isinstance(response.data, dict):
|
|
# Reorder the response to place current_category before results
|
|
ordered_data = {}
|
|
for key in ['count', 'next', 'previous']:
|
|
if key in response.data:
|
|
ordered_data[key] = response.data[key]
|
|
ordered_data['current_category'] = category_data
|
|
if 'results' in response.data:
|
|
ordered_data['results'] = response.data['results']
|
|
response.data = ordered_data
|
|
|
|
return response
|
|
|
|
def get_queryset(self):
|
|
category_slug = self.kwargs.get('category_slug')
|
|
if not HadisCategory.objects.filter(slug=category_slug).exists():
|
|
return Hadis.objects.none()
|
|
|
|
queryset = Hadis.objects.filter(
|
|
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')
|
|
|
|
# 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:
|
|
from apps.bookmark.models.bookmark import Bookmark
|
|
bookmarked_ids = Bookmark.objects.filter(
|
|
user=self.request.user,
|
|
service=Bookmark.ServiceChoices.HADITH,
|
|
status=True
|
|
).values_list('content_id', flat=True)
|
|
queryset = queryset.filter(id__in=bookmarked_ids)
|
|
|
|
return queryset
|
|
|
|
def get_serializer_context(self):
|
|
"""Add user bookmarks to serializer context to avoid caching issues"""
|
|
context = super().get_serializer_context()
|
|
|
|
# Add user's bookmarked hadis IDs to context
|
|
user = self.request.user
|
|
if user.is_authenticated:
|
|
from apps.bookmark.models.bookmark import Bookmark
|
|
user_bookmarks = Bookmark.objects.filter(
|
|
user=user,
|
|
service=Bookmark.ServiceChoices.HADITH,
|
|
status=True
|
|
).values_list('content_id', flat=True)
|
|
context['user_bookmarked_hadis_ids'] = set(user_bookmarks)
|
|
else:
|
|
context['user_bookmarked_hadis_ids'] = set()
|
|
|
|
return context
|
|
|
|
|
|
|
|
|
|
class HadisMainListView(ListAPIView):
|
|
"""
|
|
API view to list Hadis by category_id
|
|
"""
|
|
serializer_class = HadisListSerializer
|
|
authentication_classes = [TokenAuthentication]
|
|
permission_classes = [IsAuthenticated]
|
|
pagination_class = StandardResultsSetPagination
|
|
|
|
@hadis_main_list_swagger
|
|
def get(self, request, *args, **kwargs):
|
|
return self.list(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
# queryset = Hadis.objects.select_related('category', 'hadis_status')
|
|
queryset = Hadis.objects.select_related('category__sect', 'hadis_status')
|
|
|
|
# Get search parameters
|
|
search_query = self.request.query_params.get('search', None)
|
|
status_filter = self.request.query_params.get('status', None)
|
|
category_filter = self.request.query_params.get('category', None)
|
|
|
|
# Apply search filter
|
|
if search_query:
|
|
queryset = self.apply_search_filter(queryset, search_query)
|
|
|
|
# Apply status filter
|
|
if status_filter:
|
|
queryset = queryset.filter(hadis_status__title__icontains=status_filter)
|
|
|
|
# Apply category filter
|
|
if category_filter:
|
|
queryset = queryset.filter(category__title__icontains=category_filter)
|
|
|
|
# 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:
|
|
from apps.bookmark.models.bookmark import Bookmark
|
|
bookmarked_ids = Bookmark.objects.filter(
|
|
user=self.request.user,
|
|
service=Bookmark.ServiceChoices.HADITH,
|
|
status=True
|
|
).values_list('content_id', flat=True)
|
|
queryset = queryset.filter(id__in=bookmarked_ids)
|
|
|
|
return queryset
|
|
|
|
def list(self, request, *args, **kwargs):
|
|
queryset = self.get_queryset()
|
|
|
|
# Apply pagination
|
|
page = self.paginate_queryset(queryset)
|
|
if page is not None:
|
|
serializer = self.get_serializer(page, many=True)
|
|
paginated_response = self.get_paginated_response(serializer.data)
|
|
|
|
# Get category titles
|
|
category_titles = self.get_category_titles(request)
|
|
|
|
# Get status titles
|
|
status_titles = self.get_status_titles(request)
|
|
|
|
# Modify the paginated response to include our custom data
|
|
response_data = paginated_response.data
|
|
# response_data['category_titles'] = self.get_cached_category_titles(request)
|
|
# response_data['status_titles'] = self.get_cached_status_titles(request)
|
|
|
|
return Response(response_data)
|
|
|
|
# Fallback for when pagination is disabled
|
|
serializer = self.get_serializer(queryset, many=True)
|
|
return Response({
|
|
'count': queryset.count(),
|
|
'results': serializer.data
|
|
})
|
|
|
|
return Response(response_data)
|
|
|
|
def get_category_titles(self,request):
|
|
"""Get list of category titles based on language"""
|
|
from ..models import HadisCategory
|
|
|
|
categories = HadisCategory.objects.all()
|
|
category_titles = []
|
|
|
|
for category in categories:
|
|
title = get_localized_text(category.title,request)
|
|
category_titles.append(title)
|
|
|
|
return category_titles
|
|
|
|
def get_status_titles(self, request):
|
|
"""Get list of status titles based on language"""
|
|
from ..models import HadisStatus
|
|
|
|
statuses = HadisStatus.objects.all().order_by('order')
|
|
status_titles = []
|
|
|
|
for status in statuses:
|
|
title = get_localized_text(status.title,request)
|
|
status_titles.append(title)
|
|
return status_titles
|
|
|
|
def apply_search_filter(self, queryset, search_query):
|
|
"""
|
|
Apply search filter across multiple fields including JSONFields.
|
|
Searches in: title, title_narrator, text, translation
|
|
"""
|
|
from django.db.models import Q
|
|
|
|
# Basic search conditions
|
|
search_conditions = Q(text__icontains=search_query)
|
|
|
|
# For JSONFields, search in the JSON string representation
|
|
# This will find matches in the "text" values within the JSON arrays
|
|
search_conditions |= Q(title__icontains=search_query)
|
|
search_conditions |= Q(title_narrator__icontains=search_query)
|
|
search_conditions |= Q(translation__icontains=search_query)
|
|
|
|
return queryset.filter(search_conditions)
|
|
|
|
#we add this later
|
|
|
|
# def get_cached_category_titles(self, request):
|
|
# """Fetches categories, cached for 1 hour to reduce DB load"""
|
|
# lang = getattr(request, "LANGUAGE_CODE", "en")
|
|
# cache_key = f"hadis_meta_categories_{lang}"
|
|
|
|
# data = cache.get(cache_key)
|
|
# if not data:
|
|
# # If not in cache, fetch from DB
|
|
# from ..models import HadisCategory
|
|
# categories = HadisCategory.objects.all().only('id', 'title') # Fetch only needed fields
|
|
|
|
# # Build list
|
|
# data = [get_localized_text(c.title, request) for c in categories]
|
|
|
|
# # Save to cache
|
|
# cache.set(cache_key, data, timeout=60 * 60) # 1 Hour
|
|
|
|
# return data
|
|
|
|
# def get_cached_status_titles(self, request):
|
|
# """Fetches statuses, cached for 1 hour"""
|
|
# lang = getattr(request, "LANGUAGE_CODE", "en")
|
|
# cache_key = f"hadis_meta_statuses_{lang}"
|
|
|
|
# data = cache.get(cache_key)
|
|
# if not data:
|
|
# from ..models import HadisStatus
|
|
# statuses = HadisStatus.objects.all().order_by('order')
|
|
# data = [get_localized_text(s.title, request) for s in statuses]
|
|
# cache.set(cache_key, data, timeout=60 * 60)
|
|
|
|
# return data
|
|
|
|
|
|
class HadisBasicView(RetrieveAPIView):
|
|
"""
|
|
API view to retrieve basic Hadis information by hadis_slug
|
|
"""
|
|
serializer_class = HadisBasicSerializer
|
|
lookup_field = 'slug'
|
|
lookup_url_kwarg = 'hadis_slug'
|
|
authentication_classes = [TokenAuthentication]
|
|
|
|
@hadis_basic_swagger
|
|
def get(self, request, *args, **kwargs):
|
|
return self.retrieve(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
return Hadis.objects.filter(status=True)
|
|
|
|
def get_serializer_context(self):
|
|
"""Add user bookmarks to serializer context to avoid caching issues"""
|
|
context = super().get_serializer_context()
|
|
|
|
# Add user's bookmarked hadis IDs to context
|
|
user = self.request.user
|
|
if user.is_authenticated:
|
|
from apps.bookmark.models.bookmark import Bookmark
|
|
user_bookmarks = Bookmark.objects.filter(
|
|
user=user,
|
|
service=Bookmark.ServiceChoices.HADITH,
|
|
status=True
|
|
).values_list('content_id', flat=True)
|
|
context['user_bookmarked_hadis_ids'] = set(user_bookmarks)
|
|
else:
|
|
context['user_bookmarked_hadis_ids'] = set()
|
|
|
|
return context
|
|
|
|
|
|
class HadisDetailView(RetrieveAPIView):
|
|
"""
|
|
API view to retrieve detailed Hadis information by hadis_slug (excluding transmitters and corrections)
|
|
"""
|
|
serializer_class = HadisDetailSerializer
|
|
lookup_field = 'slug'
|
|
lookup_url_kwarg = 'hadis_slug'
|
|
|
|
@hadis_detail_swagger
|
|
def get(self, request, *args, **kwargs):
|
|
return self.retrieve(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
return Hadis.objects.filter(status=True).select_related(
|
|
'category', 'hadis_status'
|
|
).prefetch_related(
|
|
'tags',
|
|
'references__book_reference',
|
|
'references__book_reference__authors',
|
|
'references__images',
|
|
)
|
|
|
|
class HadisTransmittersView(RetrieveAPIView):
|
|
"""
|
|
Fetches a single Hadis but filters the nested Transmitters list
|
|
if a ?layer=slug param is provided.
|
|
"""
|
|
serializer_class = HadisTransmitterListSerializer
|
|
lookup_field = 'slug'
|
|
lookup_url_kwarg = 'hadis_slug'
|
|
pagination_class = NoPagination
|
|
@hadis_transmitters_swagger
|
|
def get(self, request, *args, **kwargs):
|
|
return self.retrieve(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
# 1. Get the filter param
|
|
layer_slug = self.request.query_params.get('layer')
|
|
|
|
# 2. Build the query for the "Child" (Transmitters)
|
|
# We start with the base optimization (select_related)
|
|
transmitter_qs = HadisTransmitter.objects.select_related(
|
|
'transmitter',
|
|
'narrator_layer'
|
|
).order_by('order')
|
|
|
|
# 3. Apply the filter to the Child Query (if param exists)
|
|
if layer_slug:
|
|
# Assumes 'NarratorLayer' has a 'slug' field.
|
|
# If not, use 'narrator_layer__name' or 'narrator_layer__id'.
|
|
transmitter_qs = transmitter_qs.filter(narrator_layer__slug=layer_slug)
|
|
|
|
# 4. Use the Prefetch object to inject this filtered list into the Parent
|
|
return Hadis.objects.filter(status=True).prefetch_related(
|
|
Prefetch('transmitters', queryset=transmitter_qs)
|
|
)
|
|
|
|
class HadisCorrectionsView(ListAPIView):
|
|
"""
|
|
API view to retrieve corrections for a specific hadis
|
|
"""
|
|
serializer_class = HadisCorrectionSerializer
|
|
authentication_classes = [TokenAuthentication]
|
|
permission_classes = [IsAuthenticated]
|
|
pagination_class = StandardResultsSetPagination
|
|
lookup_field = 'slug'
|
|
lookup_url_kwarg = 'hadis_slug'
|
|
|
|
@hadis_corrections_swagger
|
|
def get(self, request, *args, **kwargs):
|
|
return self.list(request, *args, **kwargs)
|
|
# hadis = self.get_object()
|
|
# corrections_data = []
|
|
|
|
# for correction in hadis.hadiscorrection_set.all():
|
|
# correction_info = {
|
|
# 'id': correction.id,
|
|
# 'title': correction.title,
|
|
# 'description': correction.description,
|
|
# 'translation': correction.translation
|
|
# }
|
|
# corrections_data.append(correction_info)
|
|
|
|
# return Response({
|
|
# 'hadis_id': hadis.id,
|
|
# 'corrections_count': len(corrections_data),
|
|
# 'corrections': corrections_data
|
|
# })
|
|
|
|
def get_queryset(self):
|
|
hadis_slug = self.kwargs.get('hadis_slug')
|
|
try:
|
|
hadis = Hadis.objects.get(slug=hadis_slug, status=True)
|
|
if not HadisCorrection.objects.filter(hadis=hadis).exists():
|
|
return Hadis.objects.none()
|
|
queryset = HadisCorrection.objects.filter(hadis=hadis)
|
|
|
|
# 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:
|
|
from apps.bookmark.models.bookmark import Bookmark
|
|
bookmarked_ids = Bookmark.objects.filter(
|
|
user=self.request.user,
|
|
service=Bookmark.ServiceChoices.HADITH_CORRECTION,
|
|
status=True
|
|
).values_list('content_id', flat=True)
|
|
queryset = queryset.filter(id__in=bookmarked_ids)
|
|
|
|
return queryset
|
|
except Hadis.DoesNotExist:
|
|
return HadisCorrection.objects.none()
|
|
|
|
|
|
|
|
class HadisLayersView(ListAPIView):
|
|
"""
|
|
API view to retrieve all narrator layers for a specific hadis
|
|
"""
|
|
serializer_class = NarratorLayerSerializer
|
|
pagination_class = NoPagination
|
|
lookup_field = 'slug'
|
|
lookup_url_kwarg = 'hadis_slug'
|
|
|
|
@hadis_layers_swagger
|
|
def get(self, request, *args, **kwargs):
|
|
return self.list(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
from ..models import NarratorLayer
|
|
|
|
hadis_slug = self.kwargs.get('hadis_slug')
|
|
|
|
# Get the hadis object to ensure it exists
|
|
hadis = get_object_or_404(Hadis, slug=hadis_slug, status=True)
|
|
|
|
# Get all distinct narrator layer IDs for this hadis
|
|
layer_ids = HadisTransmitter.objects.filter(
|
|
hadis=hadis
|
|
).values_list('narrator_layer', flat=True).distinct()
|
|
|
|
# Filter out None values (transmitters without layers)
|
|
layer_ids = [lid for lid in layer_ids if lid is not None]
|
|
|
|
# Return the layer objects ordered by number
|
|
return NarratorLayer.objects.filter(id__in=layer_ids).order_by('number')
|
|
|
|
|
|
class HadisFiltersView(ListAPIView):
|
|
"""
|
|
API view to return filter data for hadis
|
|
Returns statuses and categories for filtering
|
|
"""
|
|
pagination_class = NoPagination
|
|
|
|
@arguments_filters_swagger
|
|
def get(self, request, *args, **kwargs):
|
|
return self.list(request, *args, **kwargs)
|
|
|
|
def get_queryset(self):
|
|
# This view doesn't need a queryset, it returns computed data
|
|
return Hadis.objects.none()
|
|
|
|
def list(self, request, *args, **kwargs):
|
|
# Get statuses from HadisStatus model
|
|
statuses = []
|
|
for status in HadisStatus.objects.all().order_by('order'):
|
|
title_text = get_localized_text(status.title, request)
|
|
if title_text and status.slug:
|
|
statuses.append({
|
|
'text': title_text,
|
|
'slug': status.slug
|
|
})
|
|
|
|
# Get categories from HadisCategory model
|
|
categories = []
|
|
for category in HadisCategory.objects.all().order_by('order'):
|
|
title_text = get_localized_text(category.title, request)
|
|
if title_text and category.slug:
|
|
categories.append({
|
|
'text': title_text,
|
|
'slug': category.slug
|
|
})
|
|
|
|
response_data = {
|
|
'statuses': statuses,
|
|
'categories': categories
|
|
}
|
|
|
|
return Response(response_data)
|