Browse Source

fixed category and hadis issues , added original_texts

master
Mohsen Taba 5 months ago
parent
commit
a7f44f76f4
  1. 770
      apps/hadis/docs.py
  2. 19
      apps/hadis/migrations/0034_hadiscorrection_share_link.py
  3. 53
      apps/hadis/migrations/0035_transmitteroriginaltext.py
  4. 1
      apps/hadis/models/hadis.py
  5. 16
      apps/hadis/models/transmitter.py
  6. 93
      apps/hadis/serializers/category.py
  7. 48
      apps/hadis/serializers/hadis.py
  8. 6
      apps/hadis/serializers/reference.py
  9. 4
      apps/hadis/urls.py
  10. 4
      apps/hadis/views/category.py
  11. 31
      apps/hadis/views/transmitter.py

770
apps/hadis/docs.py
File diff suppressed because it is too large
View File

19
apps/hadis/migrations/0034_hadiscorrection_share_link.py

@ -0,0 +1,19 @@
# Generated by Django 5.2.9 on 2025-12-14 10:48
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0033_hadiscorrection"),
]
operations = [
migrations.AddField(
model_name="hadiscorrection",
name="share_link",
field=models.CharField(
blank=True, max_length=255, null=True, verbose_name="share link"
),
),
]

53
apps/hadis/migrations/0035_transmitteroriginaltext.py

@ -0,0 +1,53 @@
# Generated by Django 5.2.9 on 2025-12-14 11:47
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("hadis", "0034_hadiscorrection_share_link"),
]
operations = [
migrations.CreateModel(
name="TransmitterOriginalText",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"title",
models.CharField(
blank=True, max_length=255, null=True, verbose_name="title"
),
),
("text", models.TextField(verbose_name="text")),
(
"translation",
models.JSONField(default=list, verbose_name="translation"),
),
(
"share_link",
models.CharField(
blank=True, max_length=255, null=True, verbose_name="share link"
),
),
(
"transmitter",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="originaltextes",
to="hadis.transmitters",
verbose_name="transmitter",
),
),
],
),
]

1
apps/hadis/models/hadis.py

@ -212,6 +212,7 @@ class HadisCorrection(models.Model):
translation = models.JSONField(verbose_name=_("translation"), default=list)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("created at"))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("updated at"))
share_link = models.CharField(max_length=255, verbose_name=_('share link'), null=True, blank=True)
class Meta:
verbose_name = _("Hadis Correction")

16
apps/hadis/models/transmitter.py

@ -5,6 +5,7 @@ from django.utils.translation import gettext_lazy as _
from filer.fields.image import FilerImageField
class NarratorLayer(models.Model):
"""
Model for narrator layers/classes (Tabaqat)
@ -206,3 +207,18 @@ class TransmitterOpinion(models.Model):
def __str__(self):
return f"{self.scholar_name}'s opinion on {self.transmitter.full_name} ({self.status})"
class TransmitterOriginalText(models.Model):
transmitter = models.ForeignKey(
Transmitters,
on_delete=models.CASCADE,
verbose_name=_('transmitter'),
related_name='originaltexts'
)
title = models.CharField(max_length=255, verbose_name=_('title'), null=True, blank=True)
text = models.TextField(verbose_name=_('text'))
translation = models.JSONField(verbose_name=_('translation'), default=list)
share_link = models.CharField(max_length=255, verbose_name=_('share link'), null=True, blank=True)
def __str__(self):
return f"{self.title} by {self.transmitter.full_name}"

93
apps/hadis/serializers/category.py

@ -1,5 +1,6 @@
from rest_framework import serializers
from django.utils.translation import gettext_lazy as _
from django.db.models import Count
from ..models import HadisSect, HadisCategory, Hadis , HadisCategory
@ -137,63 +138,83 @@ class HadisCategorySelectSerializer(serializers.ModelSerializer):
# children = serializers.SerializerMethodField()
children_count = serializers.SerializerMethodField()
has_hadis = serializers.SerializerMethodField()
hadis_count= serializers.SerializerMethodField()
class Meta:
model = HadisCategory
fields = ['id', 'title', 'source_type','slug', 'sect_id', 'sect_type','children_count','has_hadis']
# def get_name(self, obj):
# """Get category name based on request language"""
# request = self.context.get('request')
# language_code = getattr(request, 'LANGUAGE_CODE', 'en')
# return obj.get_translation(language_code) if hasattr(obj, 'get_translation') else obj.title
fields = ['id', 'title', 'source_type','slug', 'sect_id',
'sect_type','children_count','has_hadis','hadis_count']
def get_has_hadis(self, obj):
"""Check if category can have hadis (no active children) and has hadis"""
children = obj.get_children().filter(sect=obj.sect).order_by('order')
for child in children:
if Hadis.objects.filter(category=child, status=True).exists() :
return True
# Check if category has active children
has_active_children = obj.get_children().filter(sect=obj.sect).exists()
# If has active children, cannot have hadis
if has_active_children:
return False
# def get_thumbnail(self, obj):
# """Get absolute URL for thumbnail"""
# if hasattr(obj, 'thumbnail') and obj.thumbnail:
# request = self.context.get('request')
# if request:
# return request.build_absolute_uri(obj.thumbnail.url)
# return obj.thumbnail.url
# return None
# If no active children, check if has hadis
return Hadis.objects.filter(category=obj, status=True).exists()
def get_children_count(self, obj):
"""Get count of active children categories that have children or hadis"""
children = obj.get_children().filter(sect=obj.sect)
# Filter children that have either children or hadis
filtered_children = []
for child in children:
has_children = child.get_children().filter(sect=obj.sect).exists()
has_hadis = Hadis.objects.filter(category=child, status=True).exists()
if has_children or has_hadis:
filtered_children.append(child)
return len(filtered_children)
return len(children)
def get_hadis_count(self,obj):
return len(Hadis.objects.filter(category=obj))
class HadisCategorySelectSourceSerializer(serializers.ModelSerializer):
"""Serializer for HadisCategory Selection Flow"""
sect_id = serializers.IntegerField(source='sect.id', read_only=True)
sect_type = serializers.CharField(source='sect.sect_type', read_only=True)
children_count = serializers.SerializerMethodField()
has_hadis = serializers.SerializerMethodField()
hadis_count = serializers.SerializerMethodField()
class Meta:
model = HadisCategory
fields = ['id', 'title', 'source_type','slug', 'sect_id',
'sect_type','children_count','has_hadis','hadis_count']
def get_has_hadis(self, obj):
"""Check if category can have hadis (no active children) and has hadis"""
# Check if category has active children
has_active_children = obj.get_children().filter(sect=obj.sect).exists()
# If has active children, cannot have hadis
if has_active_children:
return False
# If no active children, check if has hadis
return Hadis.objects.filter(category=obj, status=True).exists()
def get_children_count(self, obj):
"""Get count of active children categories that have children or hadis"""
children = obj.get_children().filter(sect=obj.sect , source_type= obj.source_type)
return len(children)
def get_hadis_count(self,obj):
return len(Hadis.objects.filter(category=obj))
class CategorySerializer(serializers.ModelSerializer):
sect_id = serializers.IntegerField(source='sect.id', read_only=True)
sect_type = serializers.CharField(source='sect.sect_type', read_only=True)
children_count = serializers.SerializerMethodField()
has_hadis =serializers.SerializerMethodField()
hadis_count=serializers.SerializerMethodField()
class Meta:
model = HadisCategory
fields = ['id', 'title', 'sect_id', 'sect_type','source_type','description','order','slug','xmind_file', 'children_count']
fields = ['id', 'title', 'sect_id', 'sect_type','source_type',
'description','slug',
'children_count','has_hadis','hadis_count']
def get_children_count(self, obj):
"""Get count of active children categories that have children or hadis"""
children = obj.get_children().filter(sect=obj.sect)
# Filter children that have either children or hadis
filtered_children = []
for child in children:
has_children = child.get_children().filter(sect=obj.sect).exists()
has_hadis = Hadis.objects.filter(category=child, status=True).exists()
if has_children or has_hadis:
filtered_children.append(child)
return len(filtered_children)
return len(children)
def get_has_hadis(self,obj):
return Hadis.objects.filter(category=obj).exists()
def get_hadis_count(self,obj):
return len(Hadis.objects.filter(category=obj))

48
apps/hadis/serializers/hadis.py

@ -5,7 +5,7 @@ from urllib3 import fields
from ..models import (
Hadis, HadisStatus, HadisTag, HadisTransmitter,
HadisReference, ReferenceImage, Transmitters, HadisCollection,
TransmitterOpinion, BookReference, BookReferenceImage, BookAuthor, HadisCorrection
TransmitterOpinion, TransmitterOriginalText, BookReference, BookReferenceImage, BookAuthor, HadisCorrection
)
from apps.library.serializers import BookSerializer
@ -148,14 +148,18 @@ class HadisListSerializer(serializers.ModelSerializer):
class Meta:
model = Hadis
fields = ['id', 'number', 'title', 'text' ,'category', 'translation']
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
'title': obj.category.title,
'slug':obj.category.slug,
'source_type':obj.category.source_type,
'sect_type':obj.category.sect.sect_type
}
return None
@ -189,7 +193,7 @@ class TransmitterSerializer(serializers.ModelSerializer):
model = Transmitters
fields = [
'id', 'full_name', 'birth_year_hijri', 'death_year_hijri',
'description','reliability','madhhab',
"known_as",'nickname','reliability','madhhab',
]
class TransmitterOpinionSerializer(serializers.ModelSerializer):
""" Serializer for TransmitterOpinions """
@ -198,6 +202,13 @@ class TransmitterOpinionSerializer(serializers.ModelSerializer):
model = TransmitterOpinion
fields = '__all__'
class TransmitterOriginalTextSerializer(serializers.ModelSerializer):
""" Serializer for TransmitterOriginalText """
class Meta:
model = TransmitterOriginalText
fields = ['id', 'title', 'text', 'translation', 'share_link']
class HadisTransmitterSerializer(serializers.ModelSerializer):
""" Serializer for HadisTransmitters """
@ -207,17 +218,6 @@ class HadisTransmitterSerializer(serializers.ModelSerializer):
class TransmitterDetailSerializer(serializers.ModelSerializer):
""" Serializer for Details of Transmitters """
opinions = TransmitterOpinionSerializer(
many=True,
read_only=True,
)
hadis_transmissions = HadisTransmitterSerializer(
source='hadis',
many=True,
read_only=True,
)
class Meta:
model = Transmitters
fields = [
@ -225,7 +225,6 @@ class TransmitterDetailSerializer(serializers.ModelSerializer):
'origin','lived_in','died_in','birth_year_hijri',
'death_year_hijri','age_at_death','reliability',
'madhhab',"in_sahih_muslim","in_sahih_bukhari","description",
"thumbnail",'opinions','hadis_transmissions'
]
@ -367,7 +366,7 @@ class HadisCorrectionSerializer(serializers.ModelSerializer):
hadis_translation = serializers.SerializerMethodField()
class Meta:
model = HadisCorrection
fields = ['id', 'title', 'description', 'hadis_translation', 'created_at', 'updated_at']
fields = ['id', 'title', 'description', 'hadis_translation','share_link', 'created_at', 'updated_at']
def get_hadis_translation(self, obj):
"""Get translation based on request language"""
@ -379,11 +378,13 @@ class HadisCorrectionSerializer(serializers.ModelSerializer):
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'
'id', 'title', 'title_narrator', 'text',
'translation', 'share_link','explanation','category'
]
def get_translation(self, obj):
@ -391,6 +392,17 @@ class HadisBasicSerializer(serializers.ModelSerializer):
request = self.context.get('request')
language_code = getattr(request, 'LANGUAGE_CODE', 'en')
return obj.get_translation(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):

6
apps/hadis/serializers/reference.py

@ -20,9 +20,13 @@ class BookReferenceSerializer(serializers.ModelSerializer):
source = 'bookreference_set'
)
volume_count = serializers.SerializerMethodField()
author = serializers.SerializerMethodField()
class Meta:
model = BookReference
fields = ['id','title','description','rate','image','volume_count']
fields = ['id','title','rate','author','description','image','volume_count']
def get_author (self,obj):
author = obj.bookauthor_set
return author.name
def get_volume_count(self,obj):
request = self.context.get('request')
return BookReference.objects.filter(title=obj.title).count()

4
apps/hadis/urls.py

@ -1,7 +1,7 @@
from django.urls import path
from .views.category import HadisCategorySectListView, HadisCategoryTreeView, CategoriesView, CategoriesBySectView, HadisCategorySelectBySectView, HadisCategorySelectBySectSourceView , HadisCategoryTreeNormalView
from .views.hadis import HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView
from .views.transmitter import TransmitterView ,TransmitterDetailView, TransmitterSyncView
from .views.transmitter import TransmitterView ,TransmitterDetailView, TransmitterSyncView,TransmitterOpinionView, TransmitterOriginalTextView
from .views.reference import BookDetailView, BookReferencesView, BookReferenceSyncView
from .views.info import HadisInfoView
@ -26,6 +26,8 @@ urlpatterns = [
path('categories/', CategoriesView.as_view(), name='categories'),
path('narrators/',TransmitterView.as_view(), name='narrators'),
path('narrators/<int:transmitters_id>',TransmitterDetailView.as_view(), name='narrator-detail'),
path('narrators/<int:transmitters_id>/opinions',TransmitterOpinionView.as_view(), name='narrator-opinions'),
path('narrators/<int:transmitters_id>/original_texts',TransmitterOriginalTextView.as_view(), name='narrator-original-texts'),
path('references/',BookReferencesView.as_view(), name='references'),
path('references/<int:bookreference_id>',BookDetailView.as_view(), name='reference-detail'),
]

4
apps/hadis/views/category.py

@ -4,7 +4,7 @@ from django.shortcuts import get_object_or_404
from utils.pagination import NoPagination
from ..models import HadisSect, HadisCategory
from ..serializers import HadisCategorySectListSerializer, HadisCategoryTreeSerializer, CategorySerializer , HadisCategorySelectSerializer
from ..serializers import HadisCategorySectListSerializer, HadisCategoryTreeSerializer, CategorySerializer , HadisCategorySelectSerializer , HadisCategorySelectSourceSerializer
from ..docs import (
hadis_sect_list_swagger,
hadis_category_tree_swagger,
@ -270,7 +270,7 @@ class HadisCategorySelectBySectSourceView(ListAPIView):
Tree view for HadisCategory filtered by sect_type, category slug and source_type.
Returns the children categories of the specified category (by slug) within the sect_type, filtered by source_type.
"""
serializer_class = HadisCategorySelectSerializer
serializer_class = HadisCategorySelectSourceSerializer
@categories_tree_by_sect_source_swagger
def get(self, request, *args, **kwargs):

31
apps/hadis/views/transmitter.py

@ -1,9 +1,11 @@
from django.contrib.admin.utils import lookup_field
from rest_framework.generics import ListAPIView , RetrieveAPIView
from rest_framework.response import Response
from ..models import Transmitters , TransmitterOpinion
from ..serializers import TransmitterSerializer , TransmitterDetailSerializer, TransmitterSyncSerializer
from ..docs import transmitter_list_swagger, transmitter_detail_swagger, transmitter_sync_swagger
from ..models import Transmitters , TransmitterOpinion, TransmitterOriginalText
from ..serializers import TransmitterSerializer , TransmitterDetailSerializer, TransmitterSyncSerializer,TransmitterOpinionSerializer, TransmitterOriginalTextSerializer
from ..docs import transmitter_list_swagger, transmitter_detail_swagger, transmitter_sync_swagger, transmitter_opinion_swagger, transmitter_original_text_swagger
from utils.pagination import NoPagination
class TransmitterView(ListAPIView):
@ -54,6 +56,29 @@ class TransmitterDetailView(RetrieveAPIView):
input = self.kwargs['transmitters_id']
return Transmitters.objects.filter(id=input)
class TransmitterOpinionView(ListAPIView):
serializer_class = TransmitterOpinionSerializer
@transmitter_opinion_swagger
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def get_queryset(self):
transmitter_id = self.kwargs['transmitters_id']
return TransmitterOpinion.objects.filter(transmitter_id=transmitter_id)
class TransmitterOriginalTextView(ListAPIView):
serializer_class = TransmitterOriginalTextSerializer
@transmitter_original_text_swagger
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def get_queryset(self):
transmitter_id = self.kwargs['transmitters_id']
return TransmitterOriginalText.objects.filter(transmitter_id=transmitter_id)
class TransmitterSyncView(ListAPIView):
"""

Loading…
Cancel
Save