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.
 
 

686 lines
24 KiB

from rest_framework import serializers
from django.utils.translation import gettext_lazy as _
from rest_framework.fields import SerializerMethodField
from urllib3 import request
from .category import LocalizedField
from .category import get_localized_text
from .category import get_localized_text
from apps.bookmark.serializers.bookmark import BookmarkStatusSerializer
from ..models import (
Hadis, HadisStatus, HadisTag, HadisTransmitter,
HadisReference, ReferenceImage, Transmitters, HadisCollection,
TransmitterOpinion, TransmitterOriginalText, BookReference, BookReferenceImage, BookAuthor, HadisCorrection
)
class HadisCollectionListSerializer(serializers.ModelSerializer):
thumbnail = serializers.SerializerMethodField()
title = LocalizedField()
summary = LocalizedField()
class Meta:
model = HadisCollection
fields = ['id', 'title', 'summary','slug', 'thumbnail']
def get_thumbnail(self, obj):
if obj.thumbnail:
request = self.context.get('request')
if request:
return request.build_absolute_uri(obj.thumbnail.url)
return obj.thumbnail.url
return None
class HadisSyncSerializer(serializers.ModelSerializer):
"""Serializer for syncing all hadis data (grouped fields)"""
detail = serializers.SerializerMethodField()
narrators = serializers.SerializerMethodField()
explanations = serializers.SerializerMethodField()
corrections = serializers.SerializerMethodField()
title =LocalizedField()
title_narrator = LocalizedField()
translation = LocalizedField()
class Meta:
model = Hadis
fields = [
# header (no-extend)
'id', 'number', 'slug', 'category_id', 'title', 'title_narrator', 'text', 'translation',
# grouped sections
'detail', 'narrators', 'explanations', 'corrections',
]
def get_detail(self, obj):
request = self.context.get('request')
# status
status_block = None
if obj.hadis_status:
status_block = {
'id': obj.hadis_status.id,
'title': get_localized_text(obj.hadis_status.title, request),
'color': obj.hadis_status.color,
}
# tags (already prefetched)
tags_block = [
{'id': tag.id, 'title': get_localized_text(tag.title, request)}
for tag in obj.tags.all()
]
# references and reference images (already prefetched)
references_block = []
reference_images_block = []
for reference in obj.references.all():
book = reference.book_reference
authors = book.authors.all() if book else []
references_block.append({
'id': reference.id,
'title': get_localized_text(book.title, request) if book else None,
'authors': [
{'id': a.id, 'name': get_localized_text(a.name, request)}
for a in authors
],
'description': book.description if book else None,
})
for img in reference.images.all():
thumb_url = None
if img.thumbnail:
thumb_url = request.build_absolute_uri(img.thumbnail.url) if request else img.thumbnail.url
reference_images_block.append({
'id': img.id,
'thumbnail': thumb_url,
'priority': img.priority,
})
return {
'address': get_localized_text(obj.address, request),
'hadis_status': status_block,
'status_text': get_localized_text(obj.hadis_status_text, request),
'share_link': obj.share_link,
'links': obj.links,
'tags': tags_block,
'references': references_block,
'reference_images': reference_images_block,
}
def get_narrators(self, obj):
request = self.context.get('request')
transmitters_data = []
for transmitter_rel in obj.transmitters.all():
t = transmitter_rel.transmitter
layer = transmitter_rel.narrator_layer
transmitters_data.append({
'id': t.id,
'name': get_localized_text(t.full_name, request),
'reliability': get_localized_text(t.reliability,request),
'layer_level': layer.number if layer else None,
'layer_name': get_localized_text(layer.name, request) if layer else None,
'is_gap': transmitter_rel.is_gap,
'birth_year_hijri': t.birth_year_hijri,
'death_year_hijri': t.death_year_hijri,
'order': transmitter_rel.order,
})
return {
'description': get_localized_text(obj.description, request),
'transmitters': transmitters_data,
}
def get_explanations(self, obj):
request = self.context.get('request')
return get_localized_text(obj.explanation, request)
def get_corrections(self, obj):
request = self.context.get('request')
corrections_data = []
for correction in obj.hadiscorrection_set.all():
corrections_data.append({
'id': correction.id,
'title': get_localized_text(correction.title, request),
'description': get_localized_text(correction.description, request),
'translation': get_localized_text(correction.translation, request),
'share_link': correction.share_link,
})
return corrections_data
class HadisListSerializer(serializers.ModelSerializer):
"""Serializer for Hadis list"""
category = serializers.SerializerMethodField()
status = serializers.SerializerMethodField()
bookmark = serializers.SerializerMethodField()
translation = LocalizedField()
title = LocalizedField()
title_narrator = LocalizedField()
class Meta:
model = Hadis
fields = ['id', 'number', 'slug', 'title', 'title_narrator', 'text',
'translation', 'category', 'status', 'bookmark', 'share_link']
def get_category(self, obj):
"""Get category id and title"""
if not obj.category:
return None
request = self.context.get('request')
# Use your helper method
title = get_localized_text(obj.category.title, request) or ""
# Safe access for sect_type to prevent crashes if sect is missing
# Note: Ensure your view uses .select_related('category__sect') for speed!
sect_type = obj.category.sect.sect_type if obj.category.sect else None
return {
'id': obj.category.id,
'title': title,
'slug': obj.category.slug,
'source_type': obj.category.source_type,
'sect_type': sect_type
}
def get_status(self, obj):
"""Get status id and title"""
if not obj.hadis_status:
return None
request = self.context.get('request')
# Use your helper method
title = get_localized_text(obj.hadis_status.title, request)
return {
'id': obj.hadis_status.id,
'title': title,
'color': obj.hadis_status.color
}
def get_bookmark(self, obj):
"""Get bookmark information for this playlist."""
request = self.context.get('request')
user = request.user if request else None
book_mark = BookmarkStatusSerializer.get_bookmark_info(
obj=obj,
user=user,
service='hadith'
)
return book_mark.get('is_bookmarked', False)
class HadisStatusSerializer(serializers.ModelSerializer):
"""Serializer for HadisStatus"""
title = LocalizedField()
class Meta:
model = HadisStatus
fields = ['id', 'title', 'color']
class HadisTagSerializer(serializers.ModelSerializer):
"""Serializer for HadisTag"""
title = LocalizedField()
class Meta:
model = HadisTag
fields = ['id', 'title']
class TransmitterSerializer(serializers.ModelSerializer):
"""Serializer for Transmitters"""
full_name = LocalizedField()
known_as = LocalizedField()
nickname = LocalizedField()
reliability = serializers.SerializerMethodField()
class Meta:
model = Transmitters
fields = [
'id', 'full_name', 'slug','birth_year_hijri', 'death_year_hijri',
"known_as",'nickname','reliability','madhhab','generation'
]
def get_reliability(self, obj):
"""Serialize the reliability foreign key"""
if obj.reliability:
return {
'id': obj.reliability.id,
'title': get_localized_text(obj.reliability.title, self.context.get('request')),
'color': obj.reliability.color
}
return None
class TransmitterShortSerializer(serializers.ModelSerializer):
"""Serializer for Transmitters"""
full_name = LocalizedField()
known_as = LocalizedField()
nickname = LocalizedField()
class Meta:
model = Transmitters
fields = [
'id', 'full_name', 'birth_year_hijri', 'death_year_hijri',
"known_as",'nickname','reliability'
]
class TransmitterOpinionSerializer(serializers.ModelSerializer):
""" Serializer for TransmitterOpinions """
scholar_name = LocalizedField()
opinion_text = LocalizedField()
status = serializers.SerializerMethodField()
class Meta:
model = TransmitterOpinion
fields = ['id','transmitter','scholar_name','opinion_text','status']
def get_status(self, obj):
"""Serialize the opinion status foreign key"""
if obj.status:
request = self.context.get('request')
return {
'id': obj.status.id,
'title': get_localized_text(obj.status.title, request),
'slug': obj.status.slug,
'color': obj.status.color
}
return None
class TransmitterOriginalTextSerializer(serializers.ModelSerializer):
""" Serializer for TransmitterOriginalText """
title = LocalizedField()
text = LocalizedField()
translation =LocalizedField()
class Meta:
model = TransmitterOriginalText
fields = ['id', 'title', 'text', 'translation', 'share_link']
class TransmitterDetailSerializer(serializers.ModelSerializer):
""" Serializer for Details of Transmitters """
full_name = LocalizedField()
known_as = LocalizedField()
nickname = LocalizedField()
kunya = LocalizedField()
origin = LocalizedField()
lived_in = LocalizedField()
died_in = LocalizedField()
description = LocalizedField()
reliability = serializers.SerializerMethodField()
class Meta:
model = Transmitters
fields = [
'id','full_name','kunya','known_as','nickname',
'origin','lived_in','died_in','birth_year_hijri',
'death_year_hijri','age_at_death','reliability',
'madhhab',"in_sahih_muslim","in_sahih_bukhari",
"description",'generation'
]
def get_reliability(self, obj):
"""Serialize the reliability foreign key"""
if obj.reliability:
return {
'id': obj.reliability.id,
'title': get_localized_text(obj.reliability.title, self.context.get('request')),
'color': obj.reliability.color
}
return None
class TransmittersFiltersSerializer(serializers.ModelSerializer):
pass
class TransmitterSyncSerializer(serializers.ModelSerializer):
"""Serializer for syncing all transmitter data for offline mode"""
biographical = serializers.SerializerMethodField()
scholars_opinions = serializers.SerializerMethodField()
original_texts = serializers.SerializerMethodField()
full_name = LocalizedField()
class Meta:
model = Transmitters
fields = [
'id', 'full_name','slug' ,'biographical', 'scholars_opinions', 'original_texts'
]
def get_biographical(self, obj):
"""Get biographical information (flattened)"""
request = self.context.get('request') # ← FIX: Define request
if obj.reliability:
r= {
'id': obj.reliability.id,
'title': get_localized_text(obj.reliability.title, self.context.get('request')),
'color': obj.reliability.color
}
else :
r= None
return {
'full_name': get_localized_text(obj.full_name, request),
'kunya': get_localized_text(obj.kunya, request),
'known_as': get_localized_text(obj.known_as, request),
'nickname': get_localized_text(obj.nickname, request),
'origin': get_localized_text(obj.origin, request),
'lived_in': get_localized_text(obj.lived_in, request),
'died_in': get_localized_text(obj.died_in, request),
'birth_year_hijri': obj.birth_year_hijri,
'death_year_hijri': obj.death_year_hijri,
'age_at_death': obj.age_at_death,
'generation': obj.generation,
'reliability': r,
'madhhab': obj.madhhab,
'in_sahih_muslim': obj.in_sahih_muslim,
'in_sahih_bukhari': obj.in_sahih_bukhari,
'description': get_localized_text(obj.description, request),
'thumbnail': obj.thumbnail.url if obj.thumbnail else None,
}
def get_scholars_opinions(self, obj):
"""Get all scholarly opinions about this transmitter"""
request = self.context.get('request') # ← FIX: Define request
return [
{
'id': opinion.id,
'scholar_name': get_localized_text(opinion.scholar_name, request),
'opinion_text': get_localized_text(opinion.opinion_text, request),
'status': {
'id': opinion.status.id,
'title': get_localized_text(opinion.status.title, request),
'slug': opinion.status.slug,
'color': opinion.status.color
} if opinion.status else None,
'created_at': opinion.created_at.isoformat() if opinion.created_at else None,
'updated_at': opinion.updated_at.isoformat() if opinion.updated_at else None,
}
for opinion in obj.opinions.all() # Already prefetched
]
def get_original_texts(self, obj):
"""Get original texts of the transmitter"""
request = self.context.get('request') # ← FIX: Define request
return [
{
'id': t.id,
'title': get_localized_text(t.title, request),
'text': get_localized_text(t.text, request),
'translation': get_localized_text(t.translation, request),
'share_link': t.share_link,
}
for t in obj.originaltexts.all() # Already prefetched
]
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'
]
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):
"""Get narrator layer slug"""
return obj.narrator_layer.slug if obj.narrator_layer else None
def get_status(self, obj):
"""Serialize the status foreign key"""
if obj.status:
request = self.context.get('request')
return {
'id': obj.status.id,
'title': get_localized_text(obj.status.title, request),
'slug': obj.status.slug,
'color': obj.status.color
}
return None
# serializers.py
class HadisTransmitterListSerializer(serializers.ModelSerializer):
"""
The 'Parent' Serializer.
It takes a HADIS object and returns the count + the list of transmitters.
"""
layer_count = serializers.SerializerMethodField()
layer_names = serializers.SerializerMethodField()
results = HadisTransmitterSerializer(
source='transmitters', # Access the 'transmitters' reverse relation
many=True,
read_only=True
)
class Meta:
model = Hadis
fields = ['id', 'layer_count','layer_names', 'results']
def get_layer_count(self, obj):
# Calculate distinct layers efficiently
return obj.transmitters.values('narrator_layer').distinct().count()
def get_layer_names(self, obj):
"""Get list of localized narrator layer names"""
request = self.context.get('request')
# Get distinct narrator layer objects (not just IDs)
layers = obj.transmitters.values_list(
'narrator_layer', flat=True
).distinct()
# Import here to get actual objects
from apps.hadis.models import NarratorLayer
layer_objects = NarratorLayer.objects.filter(id__in=layers)
# Extract localized names
layer_names = [
get_localized_text(layer.name, request=request)
for layer in layer_objects
]
return layer_names
class ReferenceImageSerializer(serializers.ModelSerializer):
"""Serializer for ReferenceImage"""
thumbnail = serializers.SerializerMethodField()
class Meta:
model = ReferenceImage
fields = ['id', 'thumbnail', 'priority']
def get_thumbnail(self, obj):
"""Get thumbnail URL"""
if obj.thumbnail:
request = self.context.get('request')
if request:
return request.build_absolute_uri(obj.thumbnail.url)
return obj.thumbnail.url
return None
class HadisReferenceSerializer(serializers.ModelSerializer):
"""Serializer for HadisReference with book and images"""
book_title = serializers.SerializerMethodField()
book_authors = serializers.SerializerMethodField()
book_description = serializers.SerializerMethodField()
class Meta:
model = HadisReference
fields = [
'id', 'book_title','book_authors', 'book_description'
]
def get_book_title(self, obj):
"""Get book title"""
# ✅ Get language from request
request = self.context.get('request')
lang = request.query_params.get('lang', 'ru') if request else 'ru'
# ✅ CALL THE MODEL METHOD!
try :
title = obj.book_reference.title.get(lang)
return title
except:
return None
# def get_book_images(self, obj):
# """Get book images"""
# try :
# images = obj.book_reference.images.all()
# return images
# except:
# return None
def get_book_authors(self, obj):
"""Get book authors"""
try :
authors = obj.book_reference.authors.all()
return authors
except:
return None
def get_book_description(self, obj):
"""Get book description"""
# ✅ Get language from request
request = self.context.get('request')
lang = request.query_params.get('lang', 'ru') if request else 'ru'
try :
description = obj.book_reference.description.get(lang)
return description
except:
return None
class HadisCorrectionSerializer(serializers.ModelSerializer):
"""Serializer for HadisCorrection"""
title = LocalizedField()
description = LocalizedField()
translation = LocalizedField()
class Meta:
model = HadisCorrection
fields = ['id', 'title','slug', 'description', 'translation','share_link']
class HadisBasicSerializer(serializers.ModelSerializer):
"""Basic serializer for Hadis with minimal information"""
translation = LocalizedField()
category = serializers.SerializerMethodField()
bookmark= serializers.SerializerMethodField()
title = LocalizedField()
title_narrator = LocalizedField()
explanation = LocalizedField()
class Meta:
model = Hadis
fields = [
'id', 'slug', 'title','bookmark', 'title_narrator', 'text',
'translation', 'share_link','explanation','category'
]
def get_category(self, obj):
"""Get category id and title"""
if obj.category:
request = self.context.get('request')
return {
'id': obj.category.id,
'title': get_localized_text(obj.title,request),
'slug':obj.category.slug,
'source_type':obj.category.source_type,
'sect_type':obj.category.sect.sect_type
}
return None
def get_bookmark(self, obj):
"""Get bookmark information for this playlist."""
request = self.context.get('request')
user = request.user if request else None
book_mark = BookmarkStatusSerializer.get_bookmark_info(
obj=obj,
user=user,
service='hadith'
)
return book_mark.get('is_bookmarked', False)
class HadisShortSerializer(serializers.ModelSerializer):
"""Basic serializer for Hadis with minimal information"""
translation = LocalizedField()
title = LocalizedField()
title_narrator = LocalizedField()
class Meta:
model = Hadis
fields = [
'id', 'slug', 'title', 'title_narrator', 'text',
'translation', 'share_link']
class HadisDetailSerializer(serializers.ModelSerializer):
"""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)
references = HadisReferenceSerializer(
many=True,
read_only=True
)
reference_images = SerializerMethodField()
hadis_status_text = LocalizedField()
address = LocalizedField()
class Meta:
model = Hadis
fields = [
'id', 'number', 'slug',
'hadis_status_text','hadis_status', 'links','share_link',
'tags', 'references','reference_images','address'
]
def get_reference_images(self, obj):
"""Get all reference images from all references"""
all_images = []
for reference in obj.references.all():
images = reference.images.all().order_by('priority')
serializer = ReferenceImageSerializer(images, many=True, context=self.context)
all_images.extend(serializer.data)
return all_images
# 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"""
request = self.context.get('request')
language_code = getattr(request, 'LANGUAGE_CODE', 'en')
return obj.translation.get(language_code)