Browse Source

feat: naraytor layer logic updated to connect to hadith directly

master
Mohsen Taba 3 weeks ago
parent
commit
bf07701b24
  1. 33
      apps/hadis/migrations/0036_alter_narratorlayer_options_narratorlayer_hadis_and_more.py
  2. 16
      apps/hadis/models/transmitter.py
  3. 18
      apps/hadis/serializers/hadis.py
  4. 31
      apps/hadis/serializers/serializers_admin.py
  5. 12
      apps/hadis/views/hadis.py
  6. 9
      apps/hadis/views_admin.py

33
apps/hadis/migrations/0036_alter_narratorlayer_options_narratorlayer_hadis_and_more.py

@ -0,0 +1,33 @@
# Generated by Django 4.2.30 on 2026-08-29 13:51
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('hadis', '0035_bookreference_has_editions'),
]
operations = [
migrations.AlterModelOptions(
name='narratorlayer',
options={'ordering': ['hadis', 'number', 'id'], 'verbose_name': 'Narrator Layer', 'verbose_name_plural': 'Narrator Layers'},
),
migrations.AddField(
model_name='narratorlayer',
name='hadis',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='narrator_layers', to='hadis.hadis', verbose_name='hadis'),
),
migrations.AlterField(
model_name='narratorlayer',
name='number',
field=models.PositiveIntegerField(verbose_name='layer number'),
),
migrations.AlterField(
model_name='narratorlayer',
name='slug',
field=models.SlugField(allow_unicode=True, blank=True, max_length=255, null=True, verbose_name='slug'),
),
]

16
apps/hadis/models/transmitter.py

@ -15,12 +15,20 @@ class NarratorLayer(LowercaseSlugMixin, models.Model):
slug_source_field = 'name'
"""
Model for narrator layers/classes (Tabaqat)
Represents the classification level of narrators in hadis chains
Represents the classification level of narrators in a specific hadis chain
"""
hadis = models.ForeignKey(
"hadis.Hadis",
on_delete=models.CASCADE,
related_name="narrator_layers",
verbose_name=_("hadis"),
null=True,
blank=True,
)
name = models.JSONField(default=list, verbose_name=_('Name'))
number = models.PositiveIntegerField(verbose_name=_('layer number'), unique=True)
number = models.PositiveIntegerField(verbose_name=_('layer number'))
description = models.JSONField(default=list, verbose_name=_('Description'))
slug = models.SlugField(max_length=255,unique=True, verbose_name=_('slug'), blank=True, allow_unicode=True)
slug = models.SlugField(max_length=255, verbose_name=_('slug'), blank=True, null=True, allow_unicode=True)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'))
@ -28,7 +36,7 @@ class NarratorLayer(LowercaseSlugMixin, models.Model):
class Meta:
verbose_name = _('Narrator Layer')
verbose_name_plural = _('Narrator Layers')
ordering = ['number']
ordering = ['hadis', 'number', 'id']
def __str__(self):
name = self.name[0]['text'] if self.name else f"Layer {self.number}"

18
apps/hadis/serializers/hadis.py

@ -730,30 +730,20 @@ class HadisTransmitterListSerializer(serializers.ModelSerializer):
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()
return obj.narrator_layers.count()
def get_layer_names(self, obj):
"""Get list of localized narrator layer names"""
request = self.context.get('request')
layer_objects = obj.narrator_layers.all().order_by('number')
# Import here to get actual objects
from apps.hadis.models import NarratorLayer
# Get ALL distinct narrator layer IDs for this hadis (not filtered)
# This ensures layer names are returned regardless of layer filtering
all_layers_for_hadis = HadisTransmitter.objects.filter(
hadis=obj
).values_list('narrator_layer', flat=True).distinct()
layer_objects = NarratorLayer.objects.filter(id__in=all_layers_for_hadis)
# Extract localized names
layer_names = []
for layer in layer_objects:
name = get_localized_text(layer.name, request=request)
description = get_localized_text(layer.description, request=request)
slug = layer.slug
layer_names.append({
'id': layer.id,
'name': name,
'slug': slug,
'description': description

31
apps/hadis/serializers/serializers_admin.py

@ -913,12 +913,37 @@ class AdminTransmitterReliabilitySerializer(serializers.ModelSerializer):
class AdminNarratorLayerSerializer(serializers.ModelSerializer):
name = serializers.JSONField()
description = serializers.JSONField()
description = serializers.JSONField(required=False, default=list)
hadis = serializers.PrimaryKeyRelatedField(
queryset=Hadis.objects.all(),
required=True,
)
hadis_detail = serializers.SerializerMethodField()
class Meta:
model = NarratorLayer
fields = ["id", "name", "number", "description", "slug", "created_at", "updated_at"]
read_only_fields = ["id", "created_at", "updated_at"]
fields = [
"id",
"hadis",
"hadis_detail",
"name",
"number",
"description",
"slug",
"created_at",
"updated_at",
]
read_only_fields = ["id", "hadis_detail", "created_at", "updated_at"]
def get_hadis_detail(self, obj):
if not obj.hadis:
return None
return {
"id": obj.hadis.id,
"number": obj.hadis.number,
"slug": obj.hadis.slug,
"title": obj.hadis.title,
}
class AdminOpinionStatusSerializer(serializers.ModelSerializer):

12
apps/hadis/views/hadis.py

@ -667,16 +667,8 @@ class HadisLayersView(ListAPIView):
# Get the hadis object to ensure it exists
hadis = get_object_or_404(Hadis, slug=hadis_slug, status=True)
# Get all distinct narrator layer IDs for this hadis
layer_ids = HadisTransmitter.objects.filter(
hadis=hadis
).values_list('narrator_layer', flat=True).distinct()
# Filter out None values (transmitters without layers)
layer_ids = [lid for lid in layer_ids if lid is not None]
# Return the layer objects ordered by number
return NarratorLayer.objects.filter(id__in=layer_ids).order_by('number')
# Return the layer objects for this hadis ordered by number
return NarratorLayer.objects.filter(hadis=hadis).order_by('number')
class HadisFiltersView(ListAPIView):

9
apps/hadis/views_admin.py

@ -216,7 +216,10 @@ class DovodiNarratorLayerViewSet(ModelViewSet):
parser_classes = (JSONParser, MultiPartParser, FormParser)
def get_queryset(self):
queryset = NarratorLayer.objects.all()
queryset = NarratorLayer.objects.select_related("hadis").all()
hadis_id = self.request.query_params.get("hadis") or self.request.query_params.get("hadis_id")
if hadis_id:
queryset = queryset.filter(hadis_id=hadis_id)
search_query = self.request.query_params.get("search")
if search_query:
queryset = queryset.filter(
@ -392,7 +395,7 @@ class AdminHadisCorrectionViewSet(ModelViewSet):
queryset = queryset.filter(
Q(title__icontains=search) | Q(text__icontains=search)
)
return queryset.order_by("priority", "created_at")
return queryset.order_by("-created_at", "-id")
def perform_create(self, serializer):
priority = self.request.data.get("priority", 1)
@ -436,7 +439,7 @@ class AdminHadisInterpretationViewSet(ModelViewSet):
queryset = queryset.filter(
Q(title__icontains=search) | Q(text__icontains=search)
)
return queryset.order_by("priority", "created_at")
return queryset.order_by("-created_at", "-id")
def perform_create(self, serializer):
priority = self.request.data.get("priority", 1)

Loading…
Cancel
Save