diff --git a/apps/hadis/docs.py b/apps/hadis/docs.py index a0aaf1c..b934b63 100644 --- a/apps/hadis/docs.py +++ b/apps/hadis/docs.py @@ -75,7 +75,13 @@ hadis_category_tree_swagger = swagger_auto_schema( "sect_type": "shia", "title": "Shi'a Collections", "description": "Shia roots", - "order": 1 + "order": 1, + "source_types": [ + "hadith", + "quran", + "quote" + ] + } }, "categories": [ @@ -105,13 +111,6 @@ hadis_category_tree_swagger = swagger_auto_schema( "thumbnail": None, "xmind_file": None, "has_xmind_file": False, - "father_category": { - "id": 10, - "name": "Tafsir", - "sect_id": 1, - "sect_type": "shia", - "source_type": "quran" - }, "children_count": 3, "children": [] } @@ -126,7 +125,12 @@ hadis_category_tree_swagger = swagger_auto_schema( "sect_type": "sunni", "title": "Sunni Collections", "description": "Sunni roots", - "order": 2 + "order": 2, + "source_types": [ + "hadith", + "quran", + "quote" + ] } }, "categories": [ @@ -640,60 +644,78 @@ hadis_transmitters_swagger = swagger_auto_schema( description="Successful retrieval of the transmission chain.", examples={ "application/json": { - "id": 1800, - "layer_count": 3, + "id": 1830, + "layer_count": 2, + "layer_names": [ + "Students of the Imams", + "Minor Narrators" + ], "results": [ { - "id": 5992, - "order": 1, - "is_gap": False, - "narrator_layer_description": "Companions of the Prophet (Sahaba)", - "layer": "sahaba", - "transmitter": { - "id": 53, - "full_name": "Abu Hurairah", - "birth_year_hijri": 18, - "death_year_hijri": 59, - "known_as": "Father of the Kitten", - "nickname": None, - "reliability": "very_reliable", - } + "id": 6609, + "order": 0, + "is_gap": False, + "narrator_layer_description": "Lesser known narrators", + "layer": "minor-narrators", + "transmitter": { + "id": 90, + "full_name": "Sahl bin Ziyad", + "birth_year_hijri": 'null', + "death_year_hijri": 255, + "known_as": 'null', + "nickname": 'null', + "reliability": 10 + }, + "status": { + "id": 10, + "title": "Weak", + "slug": "weak", + "color": "orange" + } }, { - "id": 5993, - "order": 2, - "is_gap": False, - "narrator_layer_description": "Successors (Tabi'un)", - "layer": "tabiun", - "transmitter": { - "id": 60, - "full_name": "Sa'id ibn al-Musayyib", - "birth_year_hijri": 15, - "death_year_hijri": 94, - "known_as": "Sheikh of the Tabi'un", - "nickname": None, - "reliability": "reliable", - "madhhab": "sunni", - "generation": 2 - } + "id": 6610, + "order": 1, + "is_gap": False, + "narrator_layer_description": "Lesser known narrators", + "layer": "minor-narrators", + "transmitter": { + "id": 87, + "full_name": "Yunus bin Abd al-Rahman", + "birth_year_hijri": 'null', + "death_year_hijri": 208, + "known_as": 'null', + "nickname": 'null', + "reliability": 7 + }, + "status": { + "id": 7, + "title": "Very Reliable", + "slug": "very-reliable", + "color": "green" + } }, { - "id": 5995, - "order": 3, - "is_gap": True, - "narrator_layer_description": None, - "layer": None, - "transmitter": { - "id": 59, - "full_name": "Unknown Person", - "birth_year_hijri": None, - "death_year_hijri": None, - "known_as": None, - "nickname": None, - "reliability": "unknown", - "madhhab": "unknown", - "generation": None - } + "id": 6611, + "order": 2, + "is_gap": False, + "narrator_layer_description": "Direct students of the Imams", + "layer": "students-of-the-imams", + "transmitter": { + "id": 84, + "full_name": "Zurarah bin Ayan", + "birth_year_hijri": 'null', + "death_year_hijri": 150, + "known_as": 'null', + "nickname": 'null', + "reliability": 7 + }, + "status": { + "id": 7, + "title": "Very Reliable", + "slug": "very-reliable", + "color": "green" + } } ] } diff --git a/apps/hadis/migrations/0085_hadistransmitter_hadis_hadis_hadis_i_d04e3a_idx_and_more.py b/apps/hadis/migrations/0085_hadistransmitter_hadis_hadis_hadis_i_d04e3a_idx_and_more.py new file mode 100644 index 0000000..bde1c87 --- /dev/null +++ b/apps/hadis/migrations/0085_hadistransmitter_hadis_hadis_hadis_i_d04e3a_idx_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.27 on 2025-12-24 14:10 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("hadis", "0084_hadistransmitter_status"), + ] + + operations = [ + migrations.AddIndex( + model_name="hadistransmitter", + index=models.Index( + fields=["hadis", "order"], name="hadis_hadis_hadis_i_d04e3a_idx" + ), + ), + migrations.AddIndex( + model_name="referenceimage", + index=models.Index( + fields=["reference", "priority"], name="hadis_refer_referen_a37840_idx" + ), + ), + ] diff --git a/apps/hadis/models/hadis.py b/apps/hadis/models/hadis.py index 095cc8f..54f439a 100644 --- a/apps/hadis/models/hadis.py +++ b/apps/hadis/models/hadis.py @@ -369,6 +369,10 @@ class ReferenceImage(models.Model): class Meta: + indexes = [ + # Speeds up fetching images for a reference in priority order + models.Index(fields=['reference', 'priority']), + ] verbose_name = _('Reference Image') verbose_name_plural = _('Reference Images') diff --git a/apps/hadis/models/transmitter.py b/apps/hadis/models/transmitter.py index d04fc9c..1b7fa14 100644 --- a/apps/hadis/models/transmitter.py +++ b/apps/hadis/models/transmitter.py @@ -313,6 +313,10 @@ class HadisTransmitter(models.Model): class Meta: + indexes = [ + # Speeds up fetching transmitters for a specific hadis in order + models.Index(fields=['hadis', 'order']), + ] verbose_name = _('Hadis Transmitter') verbose_name_plural = _('Hadis Transmitters') ordering = ('hadis', 'order') diff --git a/apps/hadis/serializers/hadis.py b/apps/hadis/serializers/hadis.py index 2a2ddac..935ec83 100644 --- a/apps/hadis/serializers/hadis.py +++ b/apps/hadis/serializers/hadis.py @@ -88,7 +88,7 @@ class HadisSyncSerializer(serializers.ModelSerializer): 'description': book.description if book else None, }) - for img in reference.images.all().order_by('priority'): + 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 diff --git a/apps/hadis/views/hadis.py b/apps/hadis/views/hadis.py index 51275d9..dfd4fed 100644 --- a/apps/hadis/views/hadis.py +++ b/apps/hadis/views/hadis.py @@ -7,7 +7,7 @@ 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 +from ..models import HadisCategory, Hadis, HadisCollection,HadisTransmitter , HadisCorrection ,HadisReference, HadisStatus ,ReferenceImage from ..serializers import HadisListSerializer, HadisBasicSerializer, HadisDetailSerializer, HadisCollectionListSerializer, HadisSyncSerializer,HadisCorrectionSerializer,HadisTransmitterListSerializer 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 @@ -39,15 +39,28 @@ class HadisSyncView(ListAPIView): .select_related('category', 'hadis_status') .prefetch_related( 'tags', + # 1. OPTIMIZED TRANSMITTERS Prefetch( 'transmitters', - queryset=HadisTransmitter.objects.select_related('transmitter', 'narrator_layer').order_by('order') + queryset=HadisTransmitter.objects.select_related( + 'transmitter', + 'transmitter__reliability', # <--- Fixes N+1 for reliability text + 'narrator_layer' + ).order_by('order') ), + # 2. OPTIMIZED REFERENCES Prefetch( 'references', queryset=HadisReference.objects .select_related('book_reference') - .prefetch_related('book_reference__authors', 'images') + .prefetch_related( + 'book_reference__authors', + # <--- Fixes N+1 for Image ordering + Prefetch( + 'images', + queryset=ReferenceImage.objects.order_by('priority') + ) + ) ), 'hadiscorrection_set', )