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. 97
      apps/hadis/serializers/category.py
  7. 50
      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) translation = models.JSONField(verbose_name=_("translation"), default=list)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("created at")) created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("created at"))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("updated 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: class Meta:
verbose_name = _("Hadis Correction") 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 from filer.fields.image import FilerImageField
class NarratorLayer(models.Model): class NarratorLayer(models.Model):
""" """
Model for narrator layers/classes (Tabaqat) Model for narrator layers/classes (Tabaqat)
@ -206,3 +207,18 @@ class TransmitterOpinion(models.Model):
def __str__(self): def __str__(self):
return f"{self.scholar_name}'s opinion on {self.transmitter.full_name} ({self.status})" 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}"

97
apps/hadis/serializers/category.py

@ -1,5 +1,6 @@
from rest_framework import serializers from rest_framework import serializers
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.db.models import Count
from ..models import HadisSect, HadisCategory, Hadis , HadisCategory from ..models import HadisSect, HadisCategory, Hadis , HadisCategory
@ -137,63 +138,83 @@ class HadisCategorySelectSerializer(serializers.ModelSerializer):
# children = serializers.SerializerMethodField() # children = serializers.SerializerMethodField()
children_count = serializers.SerializerMethodField() children_count = serializers.SerializerMethodField()
has_hadis = serializers.SerializerMethodField() has_hadis = serializers.SerializerMethodField()
hadis_count= serializers.SerializerMethodField()
class Meta: class Meta:
model = HadisCategory 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): def get_has_hadis(self, obj):
"""Check if category can have hadis (no active children) and has hadis""" """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
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
# 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): def get_children_count(self, obj):
"""Get count of active children categories that have children or hadis""" """Get count of active children categories that have children or hadis"""
children = obj.get_children().filter(sect=obj.sect) 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): class CategorySerializer(serializers.ModelSerializer):
sect_id = serializers.IntegerField(source='sect.id', read_only=True) sect_id = serializers.IntegerField(source='sect.id', read_only=True)
sect_type = serializers.CharField(source='sect.sect_type', read_only=True) sect_type = serializers.CharField(source='sect.sect_type', read_only=True)
children_count = serializers.SerializerMethodField() children_count = serializers.SerializerMethodField()
has_hadis =serializers.SerializerMethodField()
hadis_count=serializers.SerializerMethodField()
class Meta: class Meta:
model = HadisCategory 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): def get_children_count(self, obj):
"""Get count of active children categories that have children or hadis""" """Get count of active children categories that have children or hadis"""
children = obj.get_children().filter(sect=obj.sect) 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))

50
apps/hadis/serializers/hadis.py

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

6
apps/hadis/serializers/reference.py

@ -20,9 +20,13 @@ class BookReferenceSerializer(serializers.ModelSerializer):
source = 'bookreference_set' source = 'bookreference_set'
) )
volume_count = serializers.SerializerMethodField() volume_count = serializers.SerializerMethodField()
author = serializers.SerializerMethodField()
class Meta: class Meta:
model = BookReference 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): def get_volume_count(self,obj):
request = self.context.get('request') request = self.context.get('request')
return BookReference.objects.filter(title=obj.title).count() return BookReference.objects.filter(title=obj.title).count()

4
apps/hadis/urls.py

@ -1,7 +1,7 @@
from django.urls import path from django.urls import path
from .views.category import HadisCategorySectListView, HadisCategoryTreeView, CategoriesView, CategoriesBySectView, HadisCategorySelectBySectView, HadisCategorySelectBySectSourceView , HadisCategoryTreeNormalView from .views.category import HadisCategorySectListView, HadisCategoryTreeView, CategoriesView, CategoriesBySectView, HadisCategorySelectBySectView, HadisCategorySelectBySectSourceView , HadisCategoryTreeNormalView
from .views.hadis import HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView 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.reference import BookDetailView, BookReferencesView, BookReferenceSyncView
from .views.info import HadisInfoView from .views.info import HadisInfoView
@ -26,6 +26,8 @@ urlpatterns = [
path('categories/', CategoriesView.as_view(), name='categories'), path('categories/', CategoriesView.as_view(), name='categories'),
path('narrators/',TransmitterView.as_view(), name='narrators'), path('narrators/',TransmitterView.as_view(), name='narrators'),
path('narrators/<int:transmitters_id>',TransmitterDetailView.as_view(), name='narrator-detail'), 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/',BookReferencesView.as_view(), name='references'),
path('references/<int:bookreference_id>',BookDetailView.as_view(), name='reference-detail'), 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 utils.pagination import NoPagination
from ..models import HadisSect, HadisCategory from ..models import HadisSect, HadisCategory
from ..serializers import HadisCategorySectListSerializer, HadisCategoryTreeSerializer, CategorySerializer , HadisCategorySelectSerializer
from ..serializers import HadisCategorySectListSerializer, HadisCategoryTreeSerializer, CategorySerializer , HadisCategorySelectSerializer , HadisCategorySelectSourceSerializer
from ..docs import ( from ..docs import (
hadis_sect_list_swagger, hadis_sect_list_swagger,
hadis_category_tree_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. 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. 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 @categories_tree_by_sect_source_swagger
def get(self, request, *args, **kwargs): 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 django.contrib.admin.utils import lookup_field
from rest_framework.generics import ListAPIView , RetrieveAPIView from rest_framework.generics import ListAPIView , RetrieveAPIView
from rest_framework.response import Response 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 from utils.pagination import NoPagination
class TransmitterView(ListAPIView): class TransmitterView(ListAPIView):
@ -54,6 +56,29 @@ class TransmitterDetailView(RetrieveAPIView):
input = self.kwargs['transmitters_id'] input = self.kwargs['transmitters_id']
return Transmitters.objects.filter(id=input) 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): class TransmitterSyncView(ListAPIView):
""" """

Loading…
Cancel
Save