From c1bfde3aec466a1525706448a8effa486af7ef67 Mon Sep 17 00:00:00 2001 From: mohsentaba Date: Tue, 23 Jun 2026 11:43:49 +0330 Subject: [PATCH] connect objects to referencess update corrections , interpretations and original text models to connect to new logic of our references models made a new api for detail pages of these references --- apps/hadis/models/hadis.py | 20 ++++- apps/hadis/models/transmitter.py | 16 ++-- apps/hadis/serializers/hadis.py | 136 ++++++++++++++++++++++++++++++- apps/hadis/urls.py | 16 +++- apps/hadis/views/hadis.py | 37 +++++++++ apps/hadis/views/transmitter.py | 21 ++++- 6 files changed, 232 insertions(+), 14 deletions(-) diff --git a/apps/hadis/models/hadis.py b/apps/hadis/models/hadis.py index 03fb933..e8e1d5c 100644 --- a/apps/hadis/models/hadis.py +++ b/apps/hadis/models/hadis.py @@ -586,10 +586,16 @@ class HadisInterpretation(models.Model): class CorrectionReference(models.Model): correction = models.ForeignKey(HadisCorrection, on_delete=models.CASCADE, related_name='references') book_reference = models.ForeignKey(BookReference, on_delete=models.SET_NULL, null=True, blank=True) + + # 👇 فیلدهای جدید اضافه شده برای یکپارچگی + edition = models.ForeignKey('hadis.BookEdition', on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Edition')) + book_volume = models.ForeignKey('hadis.BookVolume', on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Volume Record')) + hadith_number = models.CharField(max_length=100, null=True, blank=True) - volume = models.CharField(max_length=100, null=True, blank=True) + volume = models.CharField(max_length=100, null=True, blank=True, verbose_name=_('Volume Text')) pages = models.CharField(max_length=100, null=True, blank=True) - url = models.URLField(max_length=1000, null=True, blank=True) + address = models.TextField(null=True, blank=True, verbose_name=_('Address')) # 👈 اضافه شده + url = models.URLField(max_length=1000, null=True, blank=True) # 👈 آپدیت طول به 1000 class CorrectionReferenceImage(models.Model): reference = models.ForeignKey(CorrectionReference, related_name='images', on_delete=models.CASCADE) @@ -601,10 +607,16 @@ class CorrectionReferenceImage(models.Model): class InterpretationReference(models.Model): interpretation = models.ForeignKey(HadisInterpretation, on_delete=models.CASCADE, related_name='references') book_reference = models.ForeignKey(BookReference, on_delete=models.SET_NULL, null=True, blank=True) + + # 👇 فیلدهای جدید اضافه شده برای یکپارچگی + edition = models.ForeignKey('hadis.BookEdition', on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Edition')) + book_volume = models.ForeignKey('hadis.BookVolume', on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Volume Record')) + hadith_number = models.CharField(max_length=100, null=True, blank=True) - volume = models.CharField(max_length=100, null=True, blank=True) + volume = models.CharField(max_length=100, null=True, blank=True, verbose_name=_('Volume Text')) pages = models.CharField(max_length=100, null=True, blank=True) - url = models.URLField(max_length=1000, null=True, blank=True) + address = models.TextField(null=True, blank=True, verbose_name=_('Address')) # 👈 اضافه شده + url = models.URLField(max_length=1000, null=True, blank=True) # 👈 آپدیت طول به 1000 class InterpretationReferenceImage(models.Model): reference = models.ForeignKey(InterpretationReference, related_name='images', on_delete=models.CASCADE) diff --git a/apps/hadis/models/transmitter.py b/apps/hadis/models/transmitter.py index 0e74858..9770846 100644 --- a/apps/hadis/models/transmitter.py +++ b/apps/hadis/models/transmitter.py @@ -774,11 +774,17 @@ class OriginalTextReference(models.Model): on_delete=models.CASCADE, related_name='references' ) - book_reference = models.ForeignKey(BookReference, on_delete=models.SET_NULL, null=True, blank=True) - volume = models.CharField(max_length=100, null=True, blank=True) - page = models.CharField(max_length=100, null=True, blank=True) - url = models.URLField(max_length=500, null=True, blank=True) - + book_reference = models.ForeignKey('hadis.BookReference', on_delete=models.SET_NULL, null=True, blank=True) + + # 👇 فیلدهای جدید برای هماهنگی با سیستم Edition و Volume + edition = models.ForeignKey('hadis.BookEdition', on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Edition')) + book_volume = models.ForeignKey('hadis.BookVolume', on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Volume Record')) + + # فیلدهای متنی قدیمی برای سادگی یا مواردی که هنوز ولوم ساخته نشده است + volume = models.CharField(max_length=100, null=True, blank=True, verbose_name=_('Volume Text')) + pages = models.CharField(max_length=100, null=True, blank=True) # 👈 تغییر page به pages + address = models.TextField(null=True, blank=True, verbose_name=_('Address')) + url = models.URLField(max_length=1000, null=True, blank=True) # 👈 مچ کردن طول با بقیه مدل‌ها (1000) class OriginalTextReferenceImage(models.Model): """Stores the screenshots for a specific Original Text Book Reference""" reference = models.ForeignKey(OriginalTextReference, related_name='images', on_delete=models.CASCADE) diff --git a/apps/hadis/serializers/hadis.py b/apps/hadis/serializers/hadis.py index cf77941..de1b4c9 100644 --- a/apps/hadis/serializers/hadis.py +++ b/apps/hadis/serializers/hadis.py @@ -12,7 +12,8 @@ from apps.bookmark.serializers.bookmark import BookmarkStatusSerializer from ..models import ( Hadis, HadisStatus, HadisTag, HadisTransmitter, HadisReference, ReferenceImage, Transmitters, HadisCollection, - TransmitterOpinion, TransmitterOriginalText, BookReference, BookReferenceImage, BookAuthor, HadisCorrection + TransmitterOpinion, TransmitterOriginalText, BookReference, BookReferenceImage, BookAuthor, HadisCorrection,HadisInterpretation , + CorrectionReferenceImage , InterpretationReferenceImage , OriginalTextReferenceImage,CorrectionReference,InterpretationReference,OriginalTextReference ) @@ -959,4 +960,135 @@ class NarratorRelationSerializer(serializers.ModelSerializer): 'title': get_localized_text(obj.reliability.title, self.context.get('request')), 'color': obj.reliability.color, 'main_color_code': obj.reliability.main_color_code, - } \ No newline at end of file + } + + +# --- سریالایزرهای کمکی تصاویر رفرنس --- +class CorrectionReferenceImageSerializer(serializers.ModelSerializer): + class Meta: + model = CorrectionReferenceImage + fields = ['id', 'image', 'priority'] + +class InterpretationReferenceImageSerializer(serializers.ModelSerializer): + class Meta: + model = InterpretationReferenceImage + fields = ['id', 'image', 'priority'] + +class OriginalTextReferenceImageSerializer(serializers.ModelSerializer): + class Meta: + model = OriginalTextReferenceImage + fields = ['id', 'image', 'priority'] + + +# --- سریالایزرهای جامع رفرنس‌ها (شامل اطلاعات کتاب، ادیشن و ولوم) --- +class BaseDetailedReferenceSerializer(serializers.ModelSerializer): + book_title = serializers.SerializerMethodField() + book_authors = serializers.SerializerMethodField() + edition_info = serializers.SerializerMethodField() + volume_info = serializers.SerializerMethodField() + + def get_book_title(self, obj): + if obj.book_reference: + return get_localized_text(obj.book_reference.title, self.context.get('request')) + return None + + def get_book_authors(self, obj): + if obj.book_reference: + request = self.context.get('request') + return [ + {"id": author.id, "name": get_localized_text(author.name, request)} + for author in obj.book_reference.authors.all() + ] + return [] + + def get_edition_info(self, obj): + if obj.edition: + return { + "id": obj.edition.id, + "edition_number": obj.edition.edition_number, + "publisher": obj.edition.publisher + } + return None + + def get_volume_info(self, obj): + if obj.book_volume: + return { + "id": obj.book_volume.id, + "title": obj.book_volume.title + } + return None + +class DetailedCorrectionReferenceSerializer(BaseDetailedReferenceSerializer): + images = CorrectionReferenceImageSerializer(many=True, read_only=True) + class Meta: + model = CorrectionReference + fields = ['id', 'book_title', 'book_authors', 'edition_info', 'volume_info', 'hadith_number', 'volume', 'pages', 'address', 'url', 'images'] + +class DetailedInterpretationReferenceSerializer(BaseDetailedReferenceSerializer): + images = InterpretationReferenceImageSerializer(many=True, read_only=True) + class Meta: + model = InterpretationReference + fields = ['id', 'book_title', 'book_authors', 'edition_info', 'volume_info', 'hadith_number', 'volume', 'pages', 'address', 'url', 'images'] + +class DetailedOriginalTextReferenceSerializer(BaseDetailedReferenceSerializer): + images = OriginalTextReferenceImageSerializer(many=True, read_only=True) + class Meta: + model = OriginalTextReference + fields = ['id', 'book_title', 'book_authors', 'edition_info', 'volume_info', 'volume', 'pages', 'address', 'url', 'images'] + + +# --- سریالایزرهای اصلی جزئیات (Detail Serializers) --- + +class HadisCorrectionDetailSerializer(serializers.ModelSerializer): + title = LocalizedField() + description = serializers.SerializerMethodField() + translation = LocalizedField() + references = DetailedCorrectionReferenceSerializer(many=True, read_only=True) + hadis_info = serializers.SerializerMethodField() + + class Meta: + model = HadisCorrection + fields = ['id', 'title', 'slug', 'description', 'translation', 'share_link', 'hadis_info', 'references'] + + def get_description(self, obj): + return get_localized_correction_text(obj.text, request=self.context.get('request')) + + def get_hadis_info(self, obj): + return {"id": obj.hadis.id, "number": obj.hadis.number, "slug": obj.hadis.slug} + + +class HadisInterpretationDetailSerializer(serializers.ModelSerializer): + title = LocalizedField() + translation = LocalizedField() + references = DetailedInterpretationReferenceSerializer(many=True, read_only=True) + category_info = serializers.SerializerMethodField() + + class Meta: + model = HadisInterpretation + fields = ['id', 'title', 'text', 'translation', 'priority', 'category_info', 'references'] + + def get_category_info(self, obj): + return { + "id": obj.category.id, + "slug": obj.category.slug, + "title": get_localized_text(obj.category.title, self.context.get('request')) + } + + +class TransmitterOriginalTextDetailSerializer(serializers.ModelSerializer): + title = LocalizedField() + text = LocalizedField() + translation = LocalizedField() + references = DetailedOriginalTextReferenceSerializer(many=True, read_only=True) + transmitter_info = serializers.SerializerMethodField() + + class Meta: + model = TransmitterOriginalText + fields = ['id', 'slug', 'title', 'text', 'translation', 'share_link', 'transmitter_info', 'references'] + + def get_transmitter_info(self, obj): + return { + "id": obj.transmitter.id, + "slug": obj.transmitter.slug, + "name": get_localized_text(obj.transmitter.full_name, self.context.get('request')) + } \ No newline at end of file diff --git a/apps/hadis/urls.py b/apps/hadis/urls.py index fa9796b..dc7e4ca 100644 --- a/apps/hadis/urls.py +++ b/apps/hadis/urls.py @@ -1,10 +1,13 @@ from django.urls import path, include from rest_framework.routers import SimpleRouter from .views.category import HadisCategorySectListView, HadisCategoryTreeView, CategoriesView, CategoriesBySectView, HadisCategorySelectBySectView, HadisCategorySelectBySectSourceView , HadisCategoryTreeNormalView ,test_deploy,debug_headers,HadisCategoryXMindView -from .views.hadis import HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView,HadisMainListView, HadisFiltersView, HadisLayersView,PinnedHadisCollectionListView, HadisFiltersSyncAPIView +from .views.hadis import ( + HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView,HadisMainListView, HadisFiltersView, HadisLayersView,PinnedHadisCollectionListView, HadisFiltersSyncAPIView, + HadisCorrectionDetailView, HadisInterpretationDetailView +) from .views.transmitter import ( TransmitterView ,TransmitterDetailView, TransmitterSyncView,TransmitterOpinionView, TransmitterOriginalTextView, TransmitterFiltersView, - NarratorArgumentsListView , NarratorRelationsView + NarratorArgumentsListView , NarratorRelationsView,TransmitterOriginalTextDetailView, TransmitterOriginalTextDetailView ) from .views.reference import BookDetailView, BookReferencesView, BookReferenceSyncView, BookAttributeView from .views.reference_v2 import BookReferenceV2DetailView, BookReferenceV2SyncView, BookReferenceV2ListView @@ -116,4 +119,13 @@ urlpatterns = [ # path('test/test-deploy',test_deploy , name='test'), # path('debug-headers',debug_headers , name='headers'), + # Interpretation Detail Endpoint (تفسیر بر اساس آی‌دی) + path('interpretations//', HadisInterpretationDetailView.as_view(), name='interpretation-detail'), + + # Correction Detail Endpoint (تصحیح بر اساس اسلاگ) + path('corrections//', HadisCorrectionDetailView.as_view(), name='correction-detail'), + + # Original Text Detail Endpoint (متن اصلی راوی بر اساس اسلاگ) + path('original-texts//', TransmitterOriginalTextDetailView.as_view(), name='original-text-detail'), + ] diff --git a/apps/hadis/views/hadis.py b/apps/hadis/views/hadis.py index f595fe4..3f0e2de 100644 --- a/apps/hadis/views/hadis.py +++ b/apps/hadis/views/hadis.py @@ -836,3 +836,40 @@ class HadisFiltersSyncAPIView(APIView): "sources": sources, "narrators": narrators }) + +from ..serializers.hadis import HadisCorrectionDetailSerializer, HadisInterpretationDetailSerializer +from ..models import HadisInterpretation + +class HadisCorrectionDetailView(RetrieveAPIView): + """API View to get full details of a specific HadisCorrection by slug""" + serializer_class = HadisCorrectionDetailSerializer + lookup_field = 'slug' + lookup_url_kwarg = 'correction_slug' + permission_classes = [AllowAny] + + def get_queryset(self): + return HadisCorrection.objects.all().select_related( + 'hadis' + ).prefetch_related( + 'references__book_reference__authors', + 'references__edition', + 'references__book_volume', + 'references__images' + ) + +class HadisInterpretationDetailView(RetrieveAPIView): + """API View to get full details of a specific HadisInterpretation by ID""" + serializer_class = HadisInterpretationDetailSerializer + lookup_field = 'id' + lookup_url_kwarg = 'interpretation_id' + permission_classes = [AllowAny] + + def get_queryset(self): + return HadisInterpretation.objects.all().select_related( + 'category' + ).prefetch_related( + 'references__book_reference__authors', + 'references__edition', + 'references__book_volume', + 'references__images' + ) \ No newline at end of file diff --git a/apps/hadis/views/transmitter.py b/apps/hadis/views/transmitter.py index e7a3969..8fe5b5b 100644 --- a/apps/hadis/views/transmitter.py +++ b/apps/hadis/views/transmitter.py @@ -394,4 +394,23 @@ class NarratorRelationsView(APIView): "students_count": len(students_data), "teachers": teachers_data, "students": students_data - }) \ No newline at end of file + }) + +from ..serializers.hadis import TransmitterOriginalTextDetailSerializer + +class TransmitterOriginalTextDetailView(RetrieveAPIView): + """API View to get full details of a specific TransmitterOriginalText by slug""" + serializer_class = TransmitterOriginalTextDetailSerializer + lookup_field = 'slug' + lookup_url_kwarg = 'original_text_slug' + permission_classes = [AllowAny] + + def get_queryset(self): + return TransmitterOriginalText.objects.all().select_related( + 'transmitter' + ).prefetch_related( + 'references__book_reference__authors', + 'references__edition', + 'references__book_volume', + 'references__images' + ) \ No newline at end of file