diff --git a/apps/hadis/migrations/0038_alter_booksubjectarea_options_and_more.py b/apps/hadis/migrations/0038_alter_booksubjectarea_options_and_more.py new file mode 100644 index 0000000..0d6496f --- /dev/null +++ b/apps/hadis/migrations/0038_alter_booksubjectarea_options_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 4.2.30 on 2026-08-31 17:52 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('hadis', '0037_remove_bookedition_tags_remove_bookreference_tags_and_more'), + ] + + operations = [ + migrations.AlterModelOptions( + name='booksubjectarea', + options={'ordering': ('-created_at', '-id'), 'verbose_name': 'Subject Area', 'verbose_name_plural': 'Subject Areas'}, + ), + migrations.AddField( + model_name='hadistransmitter', + name='is_uncertain', + field=models.BooleanField(default=False, help_text='Whether this transmission node is doubtful between multiple candidate narrators', verbose_name='is uncertain/doubtful'), + ), + migrations.AddField( + model_name='hadistransmitter', + name='uncertain_transmitters', + field=models.ManyToManyField(blank=True, help_text='Candidate narrators when is_uncertain is True', related_name='uncertain_hadis_nodes', to='hadis.transmitters', verbose_name='uncertain candidate transmitters'), + ), + migrations.AlterField( + model_name='hadistransmitter', + name='transmitter', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='hadises', to='hadis.transmitters', verbose_name='transmitter'), + ), + ] diff --git a/apps/hadis/models/transmitter.py b/apps/hadis/models/transmitter.py index bc0a1d8..9ecb73c 100644 --- a/apps/hadis/models/transmitter.py +++ b/apps/hadis/models/transmitter.py @@ -345,9 +345,23 @@ class HadisTransmitter(models.Model): ) transmitter = models.ForeignKey( Transmitters, - on_delete=models.CASCADE, + on_delete=models.SET_NULL, verbose_name=_('transmitter'), - related_name='hadises' + related_name='hadises', + null=True, + blank=True + ) + is_uncertain = models.BooleanField( + default=False, + verbose_name=_('is uncertain/doubtful'), + help_text=_('Whether this transmission node is doubtful between multiple candidate narrators') + ) + uncertain_transmitters = models.ManyToManyField( + Transmitters, + blank=True, + related_name='uncertain_hadis_nodes', + verbose_name=_('uncertain candidate transmitters'), + help_text=_('Candidate narrators when is_uncertain is True') ) chain_index = models.PositiveIntegerField( diff --git a/apps/hadis/serializers/hadis.py b/apps/hadis/serializers/hadis.py index 045605b..207ae0e 100644 --- a/apps/hadis/serializers/hadis.py +++ b/apps/hadis/serializers/hadis.py @@ -789,15 +789,16 @@ class TransmitterSyncSerializer(serializers.ModelSerializer): class HadisTransmitterSerializer(serializers.ModelSerializer): - """Serializer for HadisTransmitter with transmitter details""" transmitter = TransmitterShortSerializer(read_only=True) + uncertain_transmitters = TransmitterShortSerializer(many=True, read_only=True) layer = serializers.SerializerMethodField() status = serializers.SerializerMethodField() + class Meta: model = HadisTransmitter fields = [ - 'id', 'order', 'is_gap','layer', 'transmitter', 'status' + 'id', 'order', 'is_gap', 'is_uncertain', 'layer', 'transmitter', 'uncertain_transmitters', 'status' ] diff --git a/apps/hadis/serializers/serializers_admin.py b/apps/hadis/serializers/serializers_admin.py index 6f14176..6e3e2c9 100644 --- a/apps/hadis/serializers/serializers_admin.py +++ b/apps/hadis/serializers/serializers_admin.py @@ -1613,12 +1613,28 @@ class AdminCategoryQuranVerseSerializer(serializers.ModelSerializer): class AdminHadisTransmitterSerializer(serializers.ModelSerializer): + transmitter_detail = AdminTransmitterListSerializer(source="transmitter", read_only=True) + uncertain_transmitters = serializers.PrimaryKeyRelatedField( + many=True, + queryset=Transmitters.objects.all(), + required=False + ) + uncertain_transmitters_detail = AdminTransmitterListSerializer( + source="uncertain_transmitters", + many=True, + read_only=True + ) + class Meta: model = HadisTransmitter fields = [ "id", "hadis", "transmitter", + "transmitter_detail", + "is_uncertain", + "uncertain_transmitters", + "uncertain_transmitters_detail", "chain_index", "narrator_layer", "status", @@ -1626,6 +1642,20 @@ class AdminHadisTransmitterSerializer(serializers.ModelSerializer): "is_gap", ] + def create(self, validated_data): + uncertain_transmitters = validated_data.pop("uncertain_transmitters", None) + instance = super().create(validated_data) + if uncertain_transmitters is not None: + instance.uncertain_transmitters.set(uncertain_transmitters) + return instance + + def update(self, instance, validated_data): + uncertain_transmitters = validated_data.pop("uncertain_transmitters", None) + instance = super().update(instance, validated_data) + if uncertain_transmitters is not None: + instance.uncertain_transmitters.set(uncertain_transmitters) + return instance + class AdminTransmitterOpinionSerializer(serializers.ModelSerializer): scholar_name = serializers.JSONField(required=False, default=list) diff --git a/apps/hadis/views/hadis.py b/apps/hadis/views/hadis.py index 2f59388..4030a05 100644 --- a/apps/hadis/views/hadis.py +++ b/apps/hadis/views/hadis.py @@ -575,8 +575,9 @@ class HadisTransmittersView(RetrieveAPIView): # We start with the base optimization (select_related) transmitter_qs = HadisTransmitter.objects.select_related( 'transmitter', - 'narrator_layer' - ).order_by('order') + 'narrator_layer', + 'status' + ).prefetch_related('uncertain_transmitters').order_by('order') # 3. Apply the filter to the Child Query (if param exists) if layer_slug: diff --git a/apps/hadis/views_admin.py b/apps/hadis/views_admin.py index 7669b93..7e134b8 100644 --- a/apps/hadis/views_admin.py +++ b/apps/hadis/views_admin.py @@ -673,7 +673,7 @@ class AdminHadisTransmitterViewSet(ModelViewSet): parser_classes = (JSONParser, MultiPartParser, FormParser) def get_queryset(self): - queryset = HadisTransmitter.objects.all().select_related("transmitter", "narrator_layer", "status") + queryset = HadisTransmitter.objects.all().select_related("transmitter", "narrator_layer", "status").prefetch_related("uncertain_transmitters") hadis_id = self.request.query_params.get("hadis_id") if hadis_id: queryset = queryset.filter(hadis_id=hadis_id)