from rest_framework import serializers from django.utils.translation import gettext_lazy as _ from rest_framework.fields import SerializerMethodField from urllib3 import fields from ..models import ( Hadis, HadisStatus, HadisTag, HadisTransmitter, HadisReference, ReferenceImage, Transmitters, HadisCollection, TransmitterOpinion, TransmitterOriginalText, BookReference, BookReferenceImage, BookAuthor, HadisCorrection ) from apps.library.serializers import BookSerializer class HadisCollectionListSerializer(serializers.ModelSerializer): thumbnail = serializers.SerializerMethodField() class Meta: model = HadisCollection fields = ['id', 'title', '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)""" translations = serializers.SerializerMethodField() detail = serializers.SerializerMethodField() narrators = serializers.SerializerMethodField() explanations = serializers.SerializerMethodField() corrections = serializers.SerializerMethodField() class Meta: model = Hadis fields = [ # header (no-extend) 'id', 'number', 'category_id', 'title', 'title_narrator', 'text', 'translations', # grouped sections 'detail', 'narrators', 'explanations', 'corrections', ] def get_translations(self, obj): """Get all translations as {lang: text}""" # translations_dict = {} # if obj.translation and isinstance(obj.translation, list): # for tr in obj.translation: # if isinstance(tr, dict): # lang_code = tr.get('language_code') # title = tr.get('title') # if lang_code: # translations_dict[lang_code] = title # return translations_dict return obj.translation def get_detail(self, obj): """Detail group: address, status, share, links, tags, references, reference_images""" request = self.context.get('request') # status status_block = None if obj.hadis_status: status_block = { 'id': obj.hadis_status.id, 'title': obj.hadis_status.title, 'color': obj.hadis_status.color } # tags tags_block = [{'id': tag.id, 'title': tag.title} for tag in obj.tags.all()] # references and reference images references_block = [] reference_images_block = [] for reference in obj.references.select_related('book_reference').prefetch_related('book_reference__authors', 'images'): book = reference.book_reference references_block.append({ 'id': reference.id, 'title': book.title if book else None, 'authors': [{'id': a.id, 'name': a.name} for a in book.authors.all()] if book else [], 'description': book.description if book else None, }) for img in reference.images.all().order_by('priority'): 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': obj.address, 'hadis_status': status_block, 'status_text': obj.hadis_status_text, 'share_link': obj.share_link, 'links': obj.links, 'tags': tags_block, 'references': references_block, 'reference_images': reference_images_block, } def get_narrators(self, obj): """Narrators group: description + transmitters""" transmitters_data = [] for transmitter_rel in obj.transmitters.select_related('transmitter', 'narrator_layer').order_by('order'): t = transmitter_rel.transmitter transmitters_data.append({ 'id': t.id, 'name': t.full_name, 'reliability': t.reliability, 'layer_level': transmitter_rel.narrator_layer.number if transmitter_rel.narrator_layer else None, 'layer_name': transmitter_rel.narrator_layer.name if transmitter_rel.narrator_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': getattr(obj, 'description', None), 'transmitters': transmitters_data } def get_explanations(self, obj): """Explanations group""" return obj.explanation def get_corrections(self, obj): """Corrections group""" corrections_data = [] for correction in obj.hadiscorrection_set.all(): corrections_data.append({ 'id': correction.id, 'title': correction.title, 'description': correction.description, 'translation': correction.translation, 'share_link': correction.share_link, }) return corrections_data class HadisListSerializer(serializers.ModelSerializer): """Serializer for Hadis list""" category = serializers.SerializerMethodField() translation = serializers.SerializerMethodField() class Meta: model = Hadis fields = ['id', 'number', 'title','title_narrator', 'text' , 'translation','category','share_link'] def get_category(self, obj): """Get category id and title""" if obj.category: return { 'id': obj.category.id, 'title': obj.category.title, 'slug':obj.category.slug, 'source_type':obj.category.source_type, 'sect_type':obj.category.sect.sect_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) class HadisStatusSerializer(serializers.ModelSerializer): """Serializer for HadisStatus""" class Meta: model = HadisStatus fields = ['id', 'title', 'color'] class HadisTagSerializer(serializers.ModelSerializer): """Serializer for HadisTag""" class Meta: model = HadisTag fields = ['id', 'title'] class TransmitterSerializer(serializers.ModelSerializer): """Serializer for Transmitters""" class Meta: model = Transmitters fields = [ 'id', 'full_name', 'birth_year_hijri', 'death_year_hijri', "known_as",'nickname','reliability','madhhab','generation' ] class TransmitterShortSerializer(serializers.ModelSerializer): """Serializer for Transmitters""" 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 """ class Meta: model = TransmitterOpinion fields = ['id','transmitter','scholar_name','opinion_text','status'] class TransmitterOriginalTextSerializer(serializers.ModelSerializer): """ Serializer for TransmitterOriginalText """ class Meta: model = TransmitterOriginalText fields = ['id', 'title', 'text', 'translation', 'share_link'] class TransmitterDetailSerializer(serializers.ModelSerializer): """ Serializer for Details of Transmitters """ 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' ] class TransmitterSyncSerializer(serializers.ModelSerializer): """Serializer for syncing all transmitter data for offline mode""" # Biographical data group (flattened) biographical = serializers.SerializerMethodField() # Scholar's opinions group scholars_opinions = serializers.SerializerMethodField() # Original texts group original_texts = serializers.SerializerMethodField() class Meta: model = Transmitters fields = [ 'id', 'full_name', 'biographical', 'scholars_opinions', 'original_texts' ] def get_biographical(self, obj): """Get biographical information (flattened)""" return { 'full_name': obj.full_name, 'kunya': obj.kunya, 'known_as': obj.known_as, 'nickname': obj.nickname, 'origin': obj.origin, 'lived_in': obj.lived_in, 'died_in': obj.died_in, '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': obj.reliability, 'madhhab': obj.madhhab, 'in_sahih_muslim': obj.in_sahih_muslim, 'in_sahih_bukhari': obj.in_sahih_bukhari, 'description': obj.description, 'thumbnail': obj.thumbnail.url if obj.thumbnail else None, } def get_scholars_opinions(self, obj): """Get all scholarly opinions about this transmitter""" opinions = [] for opinion in obj.opinions.all(): opinions.append({ 'id': opinion.id, 'scholar_name': opinion.scholar_name, 'opinion_text': opinion.opinion_text, 'status': opinion.status, 'created_at': opinion.created_at.isoformat() if opinion.created_at else None, 'updated_at': opinion.updated_at.isoformat() if opinion.updated_at else None, }) return opinions def get_original_texts(self, obj): """Get original texts of the transmitter""" texts = [] for t in obj.originaltexts.all(): texts.append({ 'id': t.id, 'title': t.title, 'text': t.text, 'translation': t.translation, 'share_link': t.share_link, }) return texts class HadisTransmitterSerializer(serializers.ModelSerializer): """Serializer for HadisTransmitter with transmitter details""" transmitter = TransmitterShortSerializer(read_only=True) narrator_layer_description = serializers.SerializerMethodField() layer = serializers.SerializerMethodField() class Meta: model = HadisTransmitter fields = [ 'id', 'order', 'is_gap','narrator_layer_description','layer', 'transmitter' ] def get_narrator_layer_description(self, obj): """Get narrator layer description""" return obj.narrator_layer.description def get_layer(self, obj): """Get narrator layer slug""" return obj.narrator_layer.slug # 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() results = HadisTransmitterSerializer( source='transmitters', # Access the 'transmitters' reverse relation many=True, read_only=True ) class Meta: model = Hadis fields = ['id', 'layer_count', 'results'] def get_layer_count(self, obj): # Calculate distinct layers efficiently return obj.transmitters.values('narrator_layer').distinct().count() 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""" try : title = obj.book_reference.title 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""" try : description = obj.book_reference.description return description except: return None class HadisCorrectionSerializer(serializers.ModelSerializer): """Serializer for HadisCorrection""" hadis_translation = serializers.SerializerMethodField() class Meta: model = HadisCorrection fields = ['id', 'title', 'description', 'hadis_translation','share_link', 'created_at', 'updated_at'] def get_hadis_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) class HadisBasicSerializer(serializers.ModelSerializer): """Basic serializer for Hadis with minimal information""" translation = serializers.SerializerMethodField() category = serializers.SerializerMethodField() class Meta: model = Hadis fields = [ 'id', 'title', 'title_narrator', 'text', 'translation', 'share_link','explanation','category' ] 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) def get_category(self, obj): """Get category id and title""" if obj.category: return { 'id': obj.category.id, 'title': obj.category.title, 'slug':obj.category.slug, 'source_type':obj.category.source_type, 'sect_type':obj.category.sect.sect_type } return None 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() class Meta: model = Hadis fields = [ 'id', 'number', '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)