Browse Source

Add Hadis Layers API endpoint and update serializers

- Introduced a new API endpoint to retrieve narrator layers associated with a specific hadis.
- Enhanced the HadisLayersView to fetch and return unique narrator layers, including their names, slugs, and descriptions.
- Updated serializers to include the slug in the TransmitterShortSerializer and added a new NarratorLayerSerializer for layer details.
- Improved response structure and Swagger documentation for better clarity on usage and expected outputs.
master
Mohsen Taba 4 months ago
parent
commit
1c1ca88422
  1. 76
      apps/hadis/docs.py
  2. 74
      apps/hadis/serializers/hadis.py
  3. 3
      apps/hadis/urls.py
  4. 38
      apps/hadis/views/hadis.py

76
apps/hadis/docs.py

@ -808,6 +808,82 @@ hadis_corrections_swagger = swagger_auto_schema(
}
)
hadis_layers_swagger = swagger_auto_schema(
operation_description="""
Get all narrator layers (Tabaqat) associated with a specific hadis.
**Key Features:**
- Returns all unique narrator layers that appear in the transmission chain of a hadis
- Each layer includes name, slug, and description information
- Layers are ordered by their numerical order (generation/classification level)
- Useful for understanding the different generations of narrators in a hadis chain
**Usage:**
- Use this endpoint to get the narrator layers for a specific hadis
- The layers represent different generations or classifications of narrators (e.g., Sahaba, Tabi'un, etc.)
- Each layer has a localized name and description
- The slug can be used for filtering transmitters by layer
**Response Structure:**
- `count`: Total number of layers for this hadis
- `next/previous`: Pagination links (typically null for this endpoint)
- `results`: Array of layer objects with name, slug, and description
**Note:**
- Only layers that have narrators in this specific hadis are returned
- Layers are ordered by their numerical layer number
- If no layers are found, the results array will be empty
""",
operation_summary="Get Hadis Narrator Layers",
operation_id="getHadisLayers",
tags=['Dobodbi - Hadis'],
manual_parameters=[
openapi.Parameter(
'hadis_slug',
openapi.IN_PATH,
description="Slug of the hadis. Must be a valid hadis slug that exists in the system. Only active hadis (status=True) are accessible.",
type=openapi.TYPE_STRING,
required=True,
example="hadis-ru-261-f7de1cbf"
)
],
responses={
status.HTTP_200_OK: openapi.Response(
description="Successfully retrieved narrator layers for the specified hadis",
examples={
"application/json": {
"count": 2,
"next": None,
"previous": None,
"results": [
{
"name": "Students of the Imams",
"slug": "students-of-the-imams",
"description": "Direct students of the Imams of Ahl al-Bayt"
},
{
"name": "Minor Narrators",
"slug": "minor-narrators",
"description": "Lesser known narrators"
}
]
}
}
),
status.HTTP_404_NOT_FOUND: openapi.Response(
description="The specified hadis slug does not exist or the hadis is not active",
examples={
"application/json": {
"detail": "Not found."
}
}
),
status.HTTP_500_INTERNAL_SERVER_ERROR: openapi.Response(
description="Internal server error occurred while processing the request"
)
}
)
# Swagger documentation for HadisCollectionListView
hadis_collections_swagger = swagger_auto_schema(

74
apps/hadis/serializers/hadis.py

@ -293,7 +293,7 @@ class TransmitterShortSerializer(serializers.ModelSerializer):
class Meta:
model = Transmitters
fields = [
'id', 'full_name', 'birth_year_hijri', 'death_year_hijri',
'id', 'full_name', 'slug','birth_year_hijri', 'death_year_hijri',
"known_as",'nickname','reliability'
]
class TransmitterOpinionSerializer(serializers.ModelSerializer):
@ -453,20 +453,14 @@ class HadisTransmitterSerializer(serializers.ModelSerializer):
"""Serializer for HadisTransmitter with transmitter details"""
transmitter = TransmitterShortSerializer(read_only=True)
narrator_layer_description = serializers.SerializerMethodField()
layer = serializers.SerializerMethodField()
status = serializers.SerializerMethodField()
class Meta:
model = HadisTransmitter
fields = [
'id', 'order', 'is_gap','narrator_layer_description','layer', 'transmitter', 'status'
'id', 'order', 'is_gap','layer', 'transmitter', 'status'
]
def get_narrator_layer_description(self, obj):
"""Get narrator layer description"""
# ✅ Get language from request
request = self.context.get('request')
return get_localized_text(obj.narrator_layer.description,request)
def get_layer(self, obj):
@ -526,10 +520,12 @@ class HadisTransmitterListSerializer(serializers.ModelSerializer):
layer_names = []
for layer in layer_objects:
name =get_localized_text(layer.name, request=request)
description = get_localized_text(layer.description, request=request)
slug = layer.slug
layer_names.append({
'name': name,
'slug': slug
'slug': slug,
'description': description
})
return layer_names
@ -557,12 +553,42 @@ class HadisReferenceSerializer(serializers.ModelSerializer):
book_title = serializers.SerializerMethodField()
book_authors = serializers.SerializerMethodField()
book_description = serializers.SerializerMethodField()
book_english_name = serializers.SerializerMethodField()
book_language = serializers.SerializerMethodField()
type_name = serializers.SerializerMethodField()
subject_area = serializers.SerializerMethodField()
class Meta:
model = HadisReference
fields = [
'id', 'book_title','book_authors', 'book_description'
'id', 'book_title', 'book_description', 'book_english_name',
'book_language', 'type_name', 'subject_area','book_authors'
]
def get_type_name(self,obj):
return "Comperhensive Shia's Hadith Encyclopedia"
def get_subject_area(self,obj):
return ["Hadith",
"Islamic History",
"Theology",
"Philosophy",
"Tafsir"
]
def get_book_english_name(self,obj):
english_name_data = obj.book_reference.title
for item in english_name_data:
if item.get('language_code') == 'en':
return item.get('text')
return None
def get_book_language(self,obj):
language_data = obj.book_reference.language
field = LocalizedField()
field._context = self.context
return field.to_representation(language_data)
def get_book_title(self, obj):
title_data = obj.book_reference.title
field = LocalizedField()
@ -585,7 +611,16 @@ class HadisReferenceSerializer(serializers.ModelSerializer):
# 3. Loop through authors and convert each object to a string (name)
# Result will be like: ["Al-Bukhari", "Muslim"]
return [field.to_representation(author.name) for author in authors]
out =[]
for author in authors:
name = field.to_representation(author.name)
out.append({
'name': name,
'birth': '1037AH/1627CE',
'death': '1105AH/1694CE',
})
return out
except Exception:
return []
@ -743,3 +778,20 @@ class HadisDetailSerializer(serializers.ModelSerializer):
request = self.context.get('request')
language_code = getattr(request, 'LANGUAGE_CODE', 'en')
return obj.translation.get(language_code)
class NarratorLayerSerializer(serializers.Serializer):
"""Serializer for narrator layers information"""
name = serializers.SerializerMethodField()
slug = serializers.CharField(read_only=True)
description = serializers.SerializerMethodField()
def get_name(self, obj):
"""Get localized name"""
request = self.context.get('request')
return get_localized_text(obj.name, request=request)
def get_description(self, obj):
"""Get localized description"""
request = self.context.get('request')
return get_localized_text(obj.description, request=request)

3
apps/hadis/urls.py

@ -1,6 +1,6 @@
from django.urls import path
from .views.category import HadisCategorySectListView, HadisCategoryTreeView, CategoriesView, CategoriesBySectView, HadisCategorySelectBySectView, HadisCategorySelectBySectSourceView , HadisCategoryTreeNormalView ,test_deploy,debug_headers
from .views.hadis import HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView,HadisMainListView, HadisFiltersView
from .views.hadis import HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView,HadisMainListView, HadisFiltersView, HadisLayersView
from .views.transmitter import TransmitterView ,TransmitterDetailView, TransmitterSyncView,TransmitterOpinionView, TransmitterOriginalTextView, TransmitterFiltersView
from .views.reference import BookDetailView, BookReferencesView, BookReferenceSyncView, BookAttributeView
from .views.version import ContentReleaseSyncView
@ -50,6 +50,7 @@ urlpatterns = [
# Hadis detail paths (with slug, more specific)
path('<str:hadis_slug>/detail/', HadisDetailView.as_view(), name='hadis-detail'),
path('<str:hadis_slug>/transmitters/', HadisTransmittersView.as_view(), name='hadis-transmitters'),
path('<str:hadis_slug>/transmitters/layers/', HadisLayersView.as_view(), name='hadis-layers'),
path('<str:hadis_slug>/corrections/', HadisCorrectionsView.as_view(), name='hadis-corrections'),
path('<str:hadis_slug>/', HadisBasicView.as_view(), name='hadis-basic'), # ← Least specific LAST

38
apps/hadis/views/hadis.py

@ -8,8 +8,8 @@ from django.db.models import Count
from django.db.models import Prefetch
from ..serializers.category import get_localized_text
from ..models import HadisCategory, Hadis, HadisCollection,HadisTransmitter , HadisCorrection ,HadisReference, HadisStatus ,ReferenceImage
from ..serializers import HadisListSerializer, HadisBasicSerializer, HadisDetailSerializer, HadisCollectionListSerializer, HadisSyncSerializer,HadisCorrectionSerializer,HadisTransmitterListSerializer , SimpleCategory
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
from ..serializers import HadisListSerializer, HadisBasicSerializer, HadisDetailSerializer, HadisCollectionListSerializer, HadisSyncSerializer,HadisCorrectionSerializer,HadisTransmitterListSerializer , SimpleCategory, NarratorLayerSerializer
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
class HadisCollectionListView(ListAPIView):
@ -437,6 +437,40 @@ class HadisCorrectionsView(ListAPIView):
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

Loading…
Cancel
Save