From 71d49e85afe4e594a21230d71bac9b8ac7b9defd Mon Sep 17 00:00:00 2001 From: mohsentaba Date: Sat, 13 Dec 2025 16:15:01 +0330 Subject: [PATCH] hadis detail url separated --- apps/hadis/docs.py | 162 +++++++++++++++++++++++++++++++- apps/hadis/serializers/hadis.py | 56 ++++++----- apps/hadis/urls.py | 9 +- apps/hadis/views/hadis.py | 98 ++++++++++++++++++- 4 files changed, 289 insertions(+), 36 deletions(-) diff --git a/apps/hadis/docs.py b/apps/hadis/docs.py index 2d0dff8..290c773 100644 --- a/apps/hadis/docs.py +++ b/apps/hadis/docs.py @@ -232,9 +232,46 @@ hadis_list_swagger = swagger_auto_schema( ) +hadis_basic_swagger = swagger_auto_schema( + operation_description="Get basic information about a specific hadis including core text and translation", + operation_summary="Get Hadis Basic Info", + operation_id="getHadisBasic", + tags=['Hadis'], + manual_parameters=[ + openapi.Parameter( + 'hadis_id', + openapi.IN_PATH, + description="ID of the hadis", + type=openapi.TYPE_INTEGER, + required=True + ) + ], + responses={ + status.HTTP_200_OK: openapi.Response( + description="Basic hadis information", + examples={ + "application/json": { + "id": 1, + "title": "The Opening", + "title_narrator": "From Abu Hurairah", + "text": "Actions are but by intention...", + "translation": "Actions are but by intention...", + "share_link": "http://example.com/hadis/1" + } + } + ), + status.HTTP_404_NOT_FOUND: openapi.Response( + description="Hadis not found" + ), + status.HTTP_500_INTERNAL_SERVER_ERROR: openapi.Response( + description="Internal server error" + ) + } +) + hadis_detail_swagger = swagger_auto_schema( - operation_summary="Get Hadis Details", - operation_description="Retrieve detailed information about a specific hadis including status, tags, transmitters, and references", + operation_summary="Get Hadis Full Details", + operation_description="Retrieve detailed information about a specific hadis including status, tags, and references (transmitters and corrections moved to separate endpoints)", tags=['Hadis'], responses={ 200: openapi.Response( @@ -349,6 +386,127 @@ hadis_detail_swagger = swagger_auto_schema( } ) +hadis_transmitters_swagger = swagger_auto_schema( + operation_description="Get all transmitters for a specific hadis including their biographical information and transmission details", + operation_summary="Get Hadis Transmitters", + operation_id="getHadisTransmitters", + tags=['Hadis'], + manual_parameters=[ + openapi.Parameter( + 'hadis_id', + openapi.IN_PATH, + description="ID of the hadis", + type=openapi.TYPE_INTEGER, + required=True + ) + ], + responses={ + status.HTTP_200_OK: openapi.Response( + description="Hadis transmitters information", + examples={ + "application/json": { + "hadis_id": 1, + "hadis_description": "This hadith emphasizes the importance of intention in all actions...", + "transmitters_count": 2, + "transmitters": [ + { + "id": 1, + "order": 1, + "is_gap": False, + "narrator_layer": "sahaba", + "transmitter": { + "id": 1, + "full_name": "Abu Hurairah", + "birth_year_hijri": 18, + "death_year_hijri": 59, + "madhhab": "sunni", + "description": "One of the most prolific narrators of hadith", + "reliability": "very_reliable" + } + }, + { + "id": 2, + "order": 2, + "is_gap": False, + "narrator_layer": "tabiin", + "transmitter": { + "id": 2, + "full_name": "Sa'id ibn al-Musayyib", + "birth_year_hijri": 15, + "death_year_hijri": 94, + "madhhab": "sunni", + "description": "Great scholar of Medina", + "reliability": "reliable" + } + } + ] + } + } + ), + status.HTTP_404_NOT_FOUND: openapi.Response( + description="Hadis not found" + ), + status.HTTP_500_INTERNAL_SERVER_ERROR: openapi.Response( + description="Internal server error" + ) + } +) + +hadis_corrections_swagger = swagger_auto_schema( + operation_description="Get all corrections for a specific hadis including translation corrections and scholarly improvements", + operation_summary="Get Hadis Corrections", + operation_id="getHadisCorrections", + tags=['Hadis'], + manual_parameters=[ + openapi.Parameter( + 'hadis_id', + openapi.IN_PATH, + description="ID of the hadis", + type=openapi.TYPE_INTEGER, + required=True + ) + ], + responses={ + status.HTTP_200_OK: openapi.Response( + description="Hadis corrections information", + examples={ + "application/json": { + "hadis_id": 1, + "corrections_count": 2, + "corrections": [ + { + "id": 1, + "title": "Translation Correction", + "description": "Corrected translation for better accuracy", + "translation": { + "en": "Actions are judged by intentions...", + "ar": "إنما الأعمال بالنيات...", + "fa": "اعمال به نیت ها قضاوت می شود..." + } + }, + { + "id": 2, + "title": "Authenticity Clarification", + "description": "Additional notes on hadith authenticity", + "translation": { + "en": "This hadith is authentic according to...", + "ar": "هذا الحديث صحيح حسب...", + "fa": "این حدیث صحیح است طبق..." + } + } + ] + } + } + ), + status.HTTP_404_NOT_FOUND: openapi.Response( + description="Hadis not found" + ), + status.HTTP_500_INTERNAL_SERVER_ERROR: openapi.Response( + description="Internal server error" + ) + } +) + # Swagger documentation for HadisCollectionListView hadis_collections_swagger = swagger_auto_schema( diff --git a/apps/hadis/serializers/hadis.py b/apps/hadis/serializers/hadis.py index 34c10be..745d20a 100644 --- a/apps/hadis/serializers/hadis.py +++ b/apps/hadis/serializers/hadis.py @@ -376,44 +376,50 @@ class HadisCorrectionSerializer(serializers.ModelSerializer): return obj.translation.get(language_code, '') +class HadisBasicSerializer(serializers.ModelSerializer): + """Basic serializer for Hadis with minimal information""" + translation = serializers.SerializerMethodField() + + class Meta: + model = Hadis + fields = [ + 'id', 'title', 'title_narrator', 'text', 'translation', 'share_link','explanation' + ] + + def get_translation(self, obj): + """Get translation based on request language""" + request = self.context.get('request') + language_code = getattr(request, 'LANGUAGE_CODE', 'en') + return obj.get_translation(language_code) + + class HadisDetailSerializer(serializers.ModelSerializer): - """Detailed serializer for Hadis with all related objects""" + """Detailed serializer for Hadis with core information (transmitters and corrections moved to separate endpoints)""" hadis_status = HadisStatusSerializer(read_only=True) tags = HadisTagSerializer(many=True, read_only=True) - transmitters = HadisTransmitterSerializer( - many=True, - read_only=True - ) references = HadisReferenceSerializer( many=True, read_only=True ) - corrections = HadisCorrectionSerializer( - source='hadiscorrection_set', - many=True, - read_only=True - ) - category = serializers.SerializerMethodField() - translation = serializers.SerializerMethodField() + # category = serializers.SerializerMethodField() class Meta: model = Hadis fields = [ - 'id', 'number', 'title', 'title_narrator','text', 'translation', 'explanation', - 'address', 'hadis_status_text', 'links','share_link', 'status', - 'category', 'hadis_status', 'tags', 'transmitters', 'description', - 'references', 'corrections' + 'id', 'number', + 'hadis_status_text','hadis_status', 'links','share_link', + 'tags', 'references','address' ] - def get_category(self, obj): - """Get category details""" - if obj.category: - return { - 'id': obj.category.id, - 'title': obj.category.title, - 'category_type': obj.category.content_type - } - return None + # def get_category(self, obj): + # """Get category details""" + # if obj.category: + # return { + # 'id': obj.category.id, + # 'title': obj.category.title, + # 'category_type': obj.category.content_type + # } + # return None def get_translation(self, obj): """Get translation based on request language""" diff --git a/apps/hadis/urls.py b/apps/hadis/urls.py index b05b7b4..f28ae83 100644 --- a/apps/hadis/urls.py +++ b/apps/hadis/urls.py @@ -1,6 +1,6 @@ from django.urls import path from .views.category import HadisCategorySectListView, HadisCategoryTreeView, CategoriesView, CategoriesBySectView, HadisCategorySelectBySectView, HadisCategorySelectBySectSourceView , HadisCategoryTreeNormalView -from .views.hadis import HadisCollectionListView, HadisListView, HadisDetailView, HadisSyncView +from .views.hadis import HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView from .views.transmitter import TransmitterView ,TransmitterDetailView, TransmitterSyncView from .views.reference import BookDetailView, BookReferencesView, BookReferenceSyncView from .views.info import HadisInfoView @@ -16,9 +16,10 @@ urlpatterns = [ path('sync/references/', BookReferenceSyncView.as_view(), name='reference-sync'), path('info/', HadisInfoView.as_view(), name='hadis-info'), path('category//', HadisListView.as_view(), name='hadis-list'), - #path('/', HadisDetailView.as_view(), name='hadis-detail'), - #path('hadis//transmitters', HadisDetailView.as_view(), name='hadis-detail'), - #path('hadis//corrections', HadisDetailView.as_view(), name='hadis-detail'), + path('/', HadisBasicView.as_view(), name='hadis-basic'), + path('/detail/', HadisDetailView.as_view(), name='hadis-detail'), + path('/transmitters/', HadisTransmittersView.as_view(), name='hadis-transmitters'), + path('/corrections/', HadisCorrectionsView.as_view(), name='hadis-corrections'), path('categories////', HadisCategorySelectBySectSourceView.as_view(), name='categories-tree-by-sect-source'), path('categories///', HadisCategorySelectBySectView.as_view(), name='categories-tree-by-sect'), path('categories//', CategoriesBySectView.as_view(), name='categories-by-sect'), diff --git a/apps/hadis/views/hadis.py b/apps/hadis/views/hadis.py index 645c249..41a1e64 100644 --- a/apps/hadis/views/hadis.py +++ b/apps/hadis/views/hadis.py @@ -4,8 +4,8 @@ from utils.pagination import NoPagination from rest_framework.response import Response from ..models import HadisCategory, Hadis, HadisCollection -from ..serializers import HadisListSerializer, HadisDetailSerializer, HadisCollectionListSerializer, HadisSyncSerializer -from ..docs import hadis_list_swagger, hadis_detail_swagger, hadis_collections_swagger, hadis_sync_swagger +from ..serializers import HadisListSerializer, HadisBasicSerializer, HadisDetailSerializer, HadisCollectionListSerializer, HadisSyncSerializer +from ..docs import hadis_list_swagger, hadis_detail_swagger, hadis_collections_swagger, hadis_sync_swagger, hadis_transmitters_swagger, hadis_corrections_swagger, hadis_basic_swagger class HadisCollectionListView(ListAPIView): @@ -79,9 +79,25 @@ class HadisListView(ListAPIView): ).order_by('number') +class HadisBasicView(RetrieveAPIView): + """ + API view to retrieve basic Hadis information by hadis_id + """ + serializer_class = HadisBasicSerializer + lookup_field = 'id' + lookup_url_kwarg = 'hadis_id' + + @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) + + class HadisDetailView(RetrieveAPIView): """ - API view to retrieve detailed Hadis information by hadis_id + API view to retrieve detailed Hadis information by hadis_id (excluding transmitters and corrections) """ serializer_class = HadisDetailSerializer lookup_field = 'id' @@ -96,11 +112,83 @@ class HadisDetailView(RetrieveAPIView): 'category', 'hadis_status' ).prefetch_related( 'tags', - 'transmitters__transmitter', 'references__book_reference__title', 'references__book_reference__images', 'references__book_reference__authors', 'references__book_reference__id', 'references__book_reference__description', - 'hadiscorrection_set', ) + + +class HadisTransmittersView(RetrieveAPIView): + """ + API view to retrieve transmitters for a specific hadis + """ + serializer_class = HadisDetailSerializer + lookup_field = 'id' + lookup_url_kwarg = 'hadis_id' + + @hadis_transmitters_swagger + def get(self, request, *args, **kwargs): + hadis = self.get_object() + transmitters_data = [] + + for transmitter_rel in hadis.transmitters.all().order_by('order'): + transmitter_info = { + 'id': transmitter_rel.id, + 'order': transmitter_rel.order, + 'is_gap': transmitter_rel.is_gap, + 'narrator_layer': transmitter_rel.narrator_layer, + 'transmitter': { + 'id': transmitter_rel.transmitter.id, + 'full_name': transmitter_rel.transmitter.full_name, + 'birth_year_hijri': transmitter_rel.transmitter.birth_year_hijri, + 'death_year_hijri': transmitter_rel.transmitter.death_year_hijri, + 'madhhab': transmitter_rel.transmitter.madhhab, + 'description': transmitter_rel.transmitter.description, + 'reliability': transmitter_rel.transmitter.reliability + } + } + transmitters_data.append(transmitter_info) + + return Response({ + 'hadis_id': hadis.id, + 'hadis_description': getattr(hadis, 'description', None), + 'transmitters_count': len(transmitters_data), + 'transmitters': transmitters_data + }) + + def get_queryset(self): + return Hadis.objects.filter(status=True).prefetch_related('transmitters__transmitter') + + +class HadisCorrectionsView(RetrieveAPIView): + """ + API view to retrieve corrections for a specific hadis + """ + serializer_class = HadisDetailSerializer + lookup_field = 'id' + lookup_url_kwarg = 'hadis_id' + + @hadis_corrections_swagger + def get(self, 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): + return Hadis.objects.filter(status=True).prefetch_related('hadiscorrection_set')