Browse Source

feat(transmitters): introduce reusable ScholarlyOpinion model and link to TransmitterOpinion

- Create ScholarlyOpinion model for standalone reusable scholarly opinions with status and multilingual text
- Add foreign key link from TransmitterOpinion to ScholarlyOpinion with automatic backward sync
- Create data migration 0053 to populate ScholarlyOpinion records from existing transmitter opinions
- Expose DovodiScholarlyOpinionViewSet and register route /dovodi-opinions/ in admin router
- Update TransmitterOpinion serializers and views to prioritize linked ScholarlyOpinion data
master
Mohsen Taba 2 weeks ago
parent
commit
d4e9f1dcfb
  1. 79
      apps/hadis/migrations/0053_scholarlyopinion_and_transmitteropinion_opinion.py
  2. 73
      apps/hadis/models/transmitter.py
  3. 59
      apps/hadis/serializers/hadis.py
  4. 37
      apps/hadis/serializers/serializers_admin.py
  5. 3
      apps/hadis/urls.py
  6. 7
      apps/hadis/views/transmitter.py
  7. 33
      apps/hadis/views_admin.py

79
apps/hadis/migrations/0053_scholarlyopinion_and_transmitteropinion_opinion.py

@ -0,0 +1,79 @@
# Generated by Django 4.2.30 on 2026-10-19 06:30
import json
from django.db import migrations, models
import django.db.models.deletion
def migrate_existing_opinions_forward(apps, schema_editor):
ScholarlyOpinion = apps.get_model("hadis", "ScholarlyOpinion")
TransmitterOpinion = apps.get_model("hadis", "TransmitterOpinion")
cache = {}
for to in TransmitterOpinion.objects.all().order_by("id"):
if to.opinion_id:
continue
raw_text = to.opinion_text if isinstance(to.opinion_text, list) else []
try:
key = (to.status_id, json.dumps(raw_text, sort_keys=True, ensure_ascii=False))
except Exception:
key = (to.status_id, str(raw_text))
scholarly_op = cache.get(key)
if scholarly_op is None:
scholarly_op = ScholarlyOpinion.objects.create(
opinion_text=raw_text,
status_id=to.status_id,
)
cache[key] = scholarly_op
to.opinion_id = scholarly_op.id
to.save(update_fields=["opinion"])
class Migration(migrations.Migration):
dependencies = [
("hadis", "0052_transmitters_gender"),
]
operations = [
migrations.CreateModel(
name="ScholarlyOpinion",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("opinion_text", models.JSONField(default=list, verbose_name="Opinion Text")),
("created_at", models.DateTimeField(auto_now_add=True, verbose_name="created at")),
("updated_at", models.DateTimeField(auto_now=True, verbose_name="updated at")),
(
"status",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="scholarly_opinions",
to="hadis.opinionstatus",
verbose_name="opinion status",
),
),
],
options={
"verbose_name": "Scholarly Opinion",
"verbose_name_plural": "Scholarly Opinions",
"ordering": ("-id",),
},
),
migrations.AddField(
model_name="transmitteropinion",
name="opinion",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="transmitter_opinions",
to="hadis.scholarlyopinion",
verbose_name="Scholarly Opinion",
),
),
migrations.RunPython(migrate_existing_opinions_forward, migrations.RunPython.noop),
]

73
apps/hadis/models/transmitter.py

@ -420,6 +420,54 @@ class OpinionStatus(ColorPaletteMixin, LowercaseSlugMixin, models.Model):
verbose_name_plural = _('Opinion Statuses') verbose_name_plural = _('Opinion Statuses')
class ScholarlyOpinion(models.Model):
"""
Standalone reusable scholarly opinion object containing status, Arabic text, and translations.
Can be connected to multiple transmitters via TransmitterOpinion.
"""
opinion_text = models.JSONField(default=list, verbose_name=_('Opinion Text'))
status = models.ForeignKey(
OpinionStatus,
on_delete=models.CASCADE,
verbose_name=_('opinion status'),
related_name='scholarly_opinions',
blank=True,
null=True
)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_('updated at'))
class Meta:
verbose_name = _('Scholarly Opinion')
verbose_name_plural = _('Scholarly Opinions')
ordering = ('-id',)
def __str__(self):
if self.opinion_text and isinstance(self.opinion_text, list) and len(self.opinion_text) > 0:
first_text = self.opinion_text[0].get('text', '') if isinstance(self.opinion_text[0], dict) else ''
return f"{first_text[:50]} ({self.status})" if first_text else f"Opinion #{self.id}"
return f"Opinion #{self.id}"
def get_opinion_tex(self, lang):
if not self.opinion_text or not isinstance(self.opinion_text, list):
return None
for tr in self.opinion_text:
if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '')
for tr in self.opinion_text:
if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '')
return None
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# Keep all connected TransmitterOpinion records synced for 100% backward compatibility
TransmitterOpinion.objects.filter(opinion_id=self.id).update(
opinion_text=self.opinion_text,
status_id=self.status_id,
)
class TransmitterOpinion(models.Model): class TransmitterOpinion(models.Model):
""" """
Model for scholarly opinions about transmitters Model for scholarly opinions about transmitters
@ -443,6 +491,14 @@ class TransmitterOpinion(models.Model):
null=True, null=True,
blank=True blank=True
) )
opinion = models.ForeignKey(
ScholarlyOpinion,
on_delete=models.CASCADE,
verbose_name=_('Scholarly Opinion'),
related_name='transmitter_opinions',
null=True,
blank=True
)
scholar_name = models.JSONField(default = list , verbose_name=_('Scholar Name')) scholar_name = models.JSONField(default = list , verbose_name=_('Scholar Name'))
opinion_text = models.JSONField(default = list , verbose_name=_('Opinion Text')) opinion_text = models.JSONField(default = list , verbose_name=_('Opinion Text'))
status = models.ForeignKey( status = models.ForeignKey(
@ -467,6 +523,15 @@ class TransmitterOpinion(models.Model):
verbose_name_plural = _('Transmitter Opinions') verbose_name_plural = _('Transmitter Opinions')
ordering = ('order', 'id') ordering = ('order', 'id')
def save(self, *args, **kwargs):
if self.opinion_id and self.opinion:
self.opinion_text = self.opinion.opinion_text
self.status_id = self.opinion.status_id
if self.scholar_id and self.scholar and not self.scholar_name:
if isinstance(self.scholar.name, list):
self.scholar_name = self.scholar.name
super().save(*args, **kwargs)
def __str__(self): def __str__(self):
scholar = self.scholar_name[0]['text'] if self.scholar_name else "Unknown Scholar" scholar = self.scholar_name[0]['text'] if self.scholar_name else "Unknown Scholar"
return f"{scholar}'s opinion on {self.transmitter} ({self.status})" return f"{scholar}'s opinion on {self.transmitter} ({self.status})"
@ -492,15 +557,15 @@ class TransmitterOpinion(models.Model):
""" """
Get title for a specific language Get title for a specific language
""" """
if not self.opinion_text or not isinstance(self.opinion_text, list):
source_text = self.opinion.opinion_text if (self.opinion_id and self.opinion) else self.opinion_text
if not source_text or not isinstance(source_text, list):
return None return None
for tr in self.opinion_text:
for tr in source_text:
if isinstance(tr, dict) and tr.get('language_code') == lang: if isinstance(tr, dict) and tr.get('language_code') == lang:
return tr.get('text', '') return tr.get('text', '')
for tr in self.opinion_text:
for tr in source_text:
if isinstance(tr, dict) and tr.get('language_code') == 'en': if isinstance(tr, dict) and tr.get('language_code') == 'en':
return tr.get('text', '') return tr.get('text', '')
return None return None

59
apps/hadis/serializers/hadis.py

@ -498,8 +498,8 @@ class TransmitterShortSerializer(serializers.ModelSerializer):
class TransmitterOpinionSerializer(serializers.ModelSerializer): class TransmitterOpinionSerializer(serializers.ModelSerializer):
""" Serializer for TransmitterOpinions """ """ Serializer for TransmitterOpinions """
scholar_name = LocalizedField() scholar_name = LocalizedField()
opinion_text = LocalizedField()
arabic_opinion_text = ArabicLocalizedField(source='opinion_text')
opinion_text = serializers.SerializerMethodField()
arabic_opinion_text = serializers.SerializerMethodField()
status = serializers.SerializerMethodField() status = serializers.SerializerMethodField()
scholar = serializers.SerializerMethodField() scholar = serializers.SerializerMethodField()
@ -507,6 +507,15 @@ class TransmitterOpinionSerializer(serializers.ModelSerializer):
model = TransmitterOpinion model = TransmitterOpinion
fields = ['id','transmitter','scholar_name','scholar','opinion_text','arabic_opinion_text','status'] fields = ['id','transmitter','scholar_name','scholar','opinion_text','arabic_opinion_text','status']
def get_opinion_text(self, obj):
request = self.context.get('request')
source_text = obj.opinion.opinion_text if (obj.opinion_id and obj.opinion) else obj.opinion_text
return get_localized_text(source_text, request)
def get_arabic_opinion_text(self, obj):
source_text = obj.opinion.opinion_text if (obj.opinion_id and obj.opinion) else obj.opinion_text
return get_arabic_localized_text(source_text)
def get_scholar(self, obj): def get_scholar(self, obj):
request = self.context.get('request') request = self.context.get('request')
if obj.scholar: if obj.scholar:
@ -519,14 +528,15 @@ class TransmitterOpinionSerializer(serializers.ModelSerializer):
def get_status(self, obj): def get_status(self, obj):
"""Serialize the opinion status foreign key""" """Serialize the opinion status foreign key"""
if obj.status:
status_obj = (obj.opinion.status if (obj.opinion_id and obj.opinion and obj.opinion.status) else obj.status)
if status_obj:
request = self.context.get('request') request = self.context.get('request')
return { return {
'id': obj.status.id,
'title': get_localized_text(obj.status.title, request),
'slug': obj.status.slug,
'color': obj.status.color,
'main_color_code': obj.status.main_color_code,
'id': status_obj.id,
'title': get_localized_text(status_obj.title, request),
'slug': status_obj.slug,
'color': status_obj.color,
'main_color_code': status_obj.main_color_code,
} }
return None return None
@ -914,30 +924,33 @@ class TransmitterSyncSerializer(serializers.ModelSerializer):
"""Get all scholarly opinions about this transmitter""" """Get all scholarly opinions about this transmitter"""
request = self.context.get('request') # ← FIX: Define request request = self.context.get('request') # ← FIX: Define request
return [
{
results = []
for opinion in obj.opinions.all():
source_text = opinion.opinion.opinion_text if (opinion.opinion_id and opinion.opinion) else opinion.opinion_text
status_obj = (opinion.opinion.status if (opinion.opinion_id and opinion.opinion and opinion.opinion.status) else opinion.status)
scholar_name_src = opinion.scholar.name if (opinion.scholar and opinion.scholar.name) else opinion.scholar_name
results.append({
'id': opinion.id, 'id': opinion.id,
'scholar_name': get_localized_text(opinion.scholar_name, request),
'arabic_scholar_name': get_arabic_localized_text(opinion.scholar_name),
'scholar_name': get_localized_text(scholar_name_src, request),
'arabic_scholar_name': get_arabic_localized_text(scholar_name_src),
'scholar': { 'scholar': {
'id': opinion.scholar.id, 'id': opinion.scholar.id,
'name': get_localized_text(opinion.scholar.name, request), 'name': get_localized_text(opinion.scholar.name, request),
'slug': opinion.scholar.slug 'slug': opinion.scholar.slug
} if opinion.scholar else None, } if opinion.scholar else None,
'opinion_text': get_localized_text(opinion.opinion_text, request),
'arabic_opinion_text': get_arabic_localized_text(opinion.opinion_text),
'opinion_text': get_localized_text(source_text, request),
'arabic_opinion_text': get_arabic_localized_text(source_text),
'status': { 'status': {
'id': opinion.status.id,
'title': get_localized_text(opinion.status.title, request),
'slug': opinion.status.slug,
'color': opinion.status.color,
'main_color_code': opinion.status.main_color_code,
} if opinion.status else None,
'id': status_obj.id,
'title': get_localized_text(status_obj.title, request),
'slug': status_obj.slug,
'color': status_obj.color,
'main_color_code': status_obj.main_color_code,
} if status_obj else None,
'created_at': opinion.created_at.isoformat() if opinion.created_at else None, 'created_at': opinion.created_at.isoformat() if opinion.created_at else None,
'updated_at': opinion.updated_at.isoformat() if opinion.updated_at else None, 'updated_at': opinion.updated_at.isoformat() if opinion.updated_at else None,
}
for opinion in obj.opinions.all() # Already prefetched
]
})
return results
def get_original_texts(self, obj): def get_original_texts(self, obj):
"""گرفتن متون اصلی راوی با جزئیات کامل و رفرنس‌ها""" """گرفتن متون اصلی راوی با جزئیات کامل و رفرنس‌ها"""

37
apps/hadis/serializers/serializers_admin.py

@ -9,7 +9,7 @@ from utils import absolute_https_url
from ..models import ( from ..models import (
Hadis, HadisCategory, HadisStatus, HadisTag, HadisCorrection, HadisInterpretation, HadisCollection, HadisSect, HadisInCollection, HadisTransmitter, HadisReference, ReferenceImage, Hadis, HadisCategory, HadisStatus, HadisTag, HadisCorrection, HadisInterpretation, HadisCollection, HadisSect, HadisInCollection, HadisTransmitter, HadisReference, ReferenceImage,
BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, BookTag, BookEdition, BookVolume, BookResearcher, BookEditor, BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, BookTag, BookEdition, BookVolume, BookResearcher, BookEditor,
Transmitters, TransmitterReliability, NarratorLayer, OpinionStatus, TransmitterOpinion, TransmitterOriginalText,
Transmitters, TransmitterReliability, NarratorLayer, OpinionStatus, ScholarlyOpinion, TransmitterOpinion, TransmitterOriginalText,
CorrectionReference, CorrectionReferenceImage, InterpretationReference, InterpretationReferenceImage, CorrectionReference, CorrectionReferenceImage, InterpretationReference, InterpretationReferenceImage,
OriginalTextReference, OriginalTextReferenceImage, OriginalTextReference, OriginalTextReferenceImage,
ContentRelease ContentRelease
@ -2733,9 +2733,33 @@ class AdminHadisTransmitterSerializer(serializers.ModelSerializer):
return instance return instance
class AdminScholarlyOpinionSerializer(serializers.ModelSerializer):
opinion_text = serializers.JSONField(required=False, default=list)
status_detail = AdminOpinionStatusSerializer(source="status", read_only=True)
transmitters_count = serializers.SerializerMethodField()
class Meta:
model = ScholarlyOpinion
fields = [
"id",
"opinion_text",
"status",
"status_detail",
"transmitters_count",
"created_at",
"updated_at",
]
def get_transmitters_count(self, obj):
if hasattr(obj, "transmitters_count_val"):
return obj.transmitters_count_val
return obj.transmitter_opinions.values("transmitter_id").distinct().count()
class AdminTransmitterOpinionSerializer(serializers.ModelSerializer): class AdminTransmitterOpinionSerializer(serializers.ModelSerializer):
scholar_name = serializers.JSONField(required=False, default=list) scholar_name = serializers.JSONField(required=False, default=list)
opinion_text = serializers.JSONField(required=False, default=list) opinion_text = serializers.JSONField(required=False, default=list)
opinion_detail = AdminScholarlyOpinionSerializer(source="opinion", read_only=True)
status_detail = AdminTransmitterReliabilitySerializer(source="status", read_only=True) status_detail = AdminTransmitterReliabilitySerializer(source="status", read_only=True)
scholar_detail = AdminBookAuthorSerializer(source="scholar", read_only=True) scholar_detail = AdminBookAuthorSerializer(source="scholar", read_only=True)
@ -2746,6 +2770,8 @@ class AdminTransmitterOpinionSerializer(serializers.ModelSerializer):
"transmitter", "transmitter",
"scholar", "scholar",
"scholar_detail", "scholar_detail",
"opinion",
"opinion_detail",
"scholar_name", "scholar_name",
"opinion_text", "opinion_text",
"status", "status",
@ -2755,6 +2781,15 @@ class AdminTransmitterOpinionSerializer(serializers.ModelSerializer):
"updated_at", "updated_at",
] ]
def to_representation(self, instance):
data = super().to_representation(instance)
if instance.opinion_id and instance.opinion:
data["opinion_text"] = instance.opinion.opinion_text
data["status"] = instance.opinion.status_id
if instance.opinion.status:
data["status_detail"] = AdminOpinionStatusSerializer(instance.opinion.status, context=self.context).data
return data
class AdminTransmitterOriginalTextSerializer(serializers.ModelSerializer): class AdminTransmitterOriginalTextSerializer(serializers.ModelSerializer):
title = serializers.JSONField(required=False, default=list) title = serializers.JSONField(required=False, default=list)

3
apps/hadis/urls.py

@ -17,7 +17,7 @@ from .views_admin import (
AdminHadisCategoryViewSet, AdminHadisViewSet, AdminHadisCorrectionViewSet, AdminCorrectionReferenceViewSet, AdminHadisReferenceViewSet, AdminInterpretationReferenceViewSet, AdminHadisInterpretationViewSet, AdminHadisStatusViewSet, AdminHadisTagViewSet, AdminHadisCollectionViewSet, AdminHadisCategoryViewSet, AdminHadisViewSet, AdminHadisCorrectionViewSet, AdminCorrectionReferenceViewSet, AdminHadisReferenceViewSet, AdminInterpretationReferenceViewSet, AdminHadisInterpretationViewSet, AdminHadisStatusViewSet, AdminHadisTagViewSet, AdminHadisCollectionViewSet,
AdminBookSubjectAreaViewSet, AdminBookTypeViewSet, AdminBookTagViewSet, AdminBookAuthorViewSet, AdminBookAttributeViewSet, AdminBookReferenceImageViewSet, AdminHadisReferenceImageViewSet, AdminBookReferenceDocumentViewSet, AdminBookReferenceViewSet, AdminBookSubjectAreaViewSet, AdminBookTypeViewSet, AdminBookTagViewSet, AdminBookAuthorViewSet, AdminBookAttributeViewSet, AdminBookReferenceImageViewSet, AdminHadisReferenceImageViewSet, AdminBookReferenceDocumentViewSet, AdminBookReferenceViewSet,
AdminTransmitterViewSet, AdminTransmitterReliabilityViewSet, DovodiBookSubjectAreaViewSet, DovodiBookTypeViewSet, AdminTransmitterViewSet, AdminTransmitterReliabilityViewSet, DovodiBookSubjectAreaViewSet, DovodiBookTypeViewSet,
DovodiNarratorLayerViewSet, DovodiTransmitterReliabilityViewSet, DovodiOpinionStatusViewSet,
DovodiNarratorLayerViewSet, DovodiTransmitterReliabilityViewSet, DovodiOpinionStatusViewSet, DovodiScholarlyOpinionViewSet,
DovodiHadisSectViewSet, DovodiHadisCategoryViewSet, AdminCategoryQuranVerseViewSet, AdminHadisTransmitterViewSet, DovodiHadisSectViewSet, DovodiHadisCategoryViewSet, AdminCategoryQuranVerseViewSet, AdminHadisTransmitterViewSet,
AdminTransmitterOpinionViewSet, AdminTransmitterOriginalTextViewSet, AdminOriginalTextReferenceViewSet, AdminBookEditionViewSet, AdminBookVolumeViewSet, AdminTransmitterOpinionViewSet, AdminTransmitterOriginalTextViewSet, AdminOriginalTextReferenceViewSet, AdminBookEditionViewSet, AdminBookVolumeViewSet,
AdminContentReleaseViewSet AdminContentReleaseViewSet
@ -59,6 +59,7 @@ admin_router.register(r'transmitter-reliabilities', AdminTransmitterReliabilityV
admin_router.register(r'dovodi-narrator-layers', DovodiNarratorLayerViewSet, basename='dovodi-narrator-layers') admin_router.register(r'dovodi-narrator-layers', DovodiNarratorLayerViewSet, basename='dovodi-narrator-layers')
admin_router.register(r'dovodi-transmitter-reliabilities', DovodiTransmitterReliabilityViewSet, basename='dovodi-transmitter-reliabilities') admin_router.register(r'dovodi-transmitter-reliabilities', DovodiTransmitterReliabilityViewSet, basename='dovodi-transmitter-reliabilities')
admin_router.register(r'dovodi-opinion-statuses', DovodiOpinionStatusViewSet, basename='dovodi-opinion-statuses') admin_router.register(r'dovodi-opinion-statuses', DovodiOpinionStatusViewSet, basename='dovodi-opinion-statuses')
admin_router.register(r'dovodi-opinions', DovodiScholarlyOpinionViewSet, basename='dovodi-opinions')
admin_router.register(r'hadis-transmitters', AdminHadisTransmitterViewSet, basename='admin-hadis-transmitters') admin_router.register(r'hadis-transmitters', AdminHadisTransmitterViewSet, basename='admin-hadis-transmitters')
admin_router.register(r'transmitter-opinions', AdminTransmitterOpinionViewSet, basename='admin-transmitter-opinions') admin_router.register(r'transmitter-opinions', AdminTransmitterOpinionViewSet, basename='admin-transmitter-opinions')
admin_router.register(r'transmitter-original-texts', AdminTransmitterOriginalTextViewSet, basename='admin-transmitter-original-texts') admin_router.register(r'transmitter-original-texts', AdminTransmitterOriginalTextViewSet, basename='admin-transmitter-original-texts')

7
apps/hadis/views/transmitter.py

@ -88,7 +88,10 @@ class TransmitterOpinionView(ListAPIView):
transmitter__slug=narrator_slug transmitter__slug=narrator_slug
).select_related( ).select_related(
'transmitter', # Essential if serializer includes transmitter data 'transmitter', # Essential if serializer includes transmitter data
'status' # Added for the new OpinionStatus ForeignKey
'status', # Added for the new OpinionStatus ForeignKey
'scholar',
'opinion',
'opinion__status',
).prefetch_related( ).prefetch_related(
# Add any nested relations from TransmitterOriginalTextSerializer # Add any nested relations from TransmitterOriginalTextSerializer
# 'translations', # 'translations',
@ -150,7 +153,7 @@ class TransmitterSyncView(ListAPIView):
.select_related('reliability') .select_related('reliability')
.prefetch_related( .prefetch_related(
# 👇 ۲. اضافه کردن 'scholar' برای جلوگیری از کوئری اضافه در نظرات دانشمندان # 👇 ۲. اضافه کردن 'scholar' برای جلوگیری از کوئری اضافه در نظرات دانشمندان
Prefetch('opinions', queryset=TransmitterOpinion.objects.select_related('status', 'scholar')),
Prefetch('opinions', queryset=TransmitterOpinion.objects.select_related('status', 'scholar', 'opinion', 'opinion__status')),
Prefetch( Prefetch(
'originaltexts', 'originaltexts',

33
apps/hadis/views_admin.py

@ -12,7 +12,7 @@ from utils.pagination import StandardResultsSetPagination, OptionalPagination
from .models import ( from .models import (
Hadis, HadisCategory, HadisCollection, HadisInCollection, HadisCorrection, HadisInterpretation, HadisStatus, HadisTag, HadisSect, HadisTransmitter, HadisReference, ReferenceImage, Hadis, HadisCategory, HadisCollection, HadisInCollection, HadisCorrection, HadisInterpretation, HadisStatus, HadisTag, HadisSect, HadisTransmitter, HadisReference, ReferenceImage,
BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, BookTag, BookEdition, BookVolume, BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, BookTag, BookEdition, BookVolume,
Transmitters, TransmitterReliability, NarratorLayer, OpinionStatus, TransmitterOpinion, TransmitterOriginalText,
Transmitters, TransmitterReliability, NarratorLayer, OpinionStatus, ScholarlyOpinion, TransmitterOpinion, TransmitterOriginalText,
CorrectionReference, InterpretationReference, OriginalTextReference, CorrectionReference, InterpretationReference, OriginalTextReference,
ContentRelease, ContentRelease,
CategoryQuranVerse, CategoryQuranVerse,
@ -49,6 +49,7 @@ from .serializers.serializers_admin import (
AdminTransmitterReliabilitySerializer, AdminTransmitterReliabilitySerializer,
AdminNarratorLayerSerializer, AdminNarratorLayerSerializer,
AdminOpinionStatusSerializer, AdminOpinionStatusSerializer,
AdminScholarlyOpinionSerializer,
AdminHadisTransmitterSerializer, AdminHadisTransmitterSerializer,
AdminTransmitterOpinionSerializer, AdminTransmitterOpinionSerializer,
AdminTransmitterOriginalTextSerializer, AdminTransmitterOriginalTextSerializer,
@ -345,6 +346,34 @@ class DovodiOpinionStatusViewSet(ModelViewSet):
return queryset.order_by("-id") return queryset.order_by("-id")
class DovodiScholarlyOpinionViewSet(ModelViewSet):
serializer_class = AdminScholarlyOpinionSerializer
permission_classes = [IsAuthenticated, IsSuperAdmin]
authentication_classes = [TokenAuthentication]
pagination_class = None
parser_classes = (JSONParser, MultiPartParser, FormParser)
def get_queryset(self):
queryset = ScholarlyOpinion.objects.select_related("status").annotate(
transmitters_count_val=Count("transmitter_opinions__transmitter", distinct=True)
)
search_query = self.request.query_params.get("search")
if search_query:
q_filter = (
Q(opinion_text__icontains=search_query)
| Q(status__title__icontains=search_query)
)
if search_query.isdigit():
q_filter |= Q(id=int(search_query))
queryset = queryset.filter(q_filter)
status_id = self.request.query_params.get("status")
if status_id and status_id != "all":
queryset = queryset.filter(status_id=status_id)
return queryset.order_by("-id")
class AdminTransmitterViewSet(ModelViewSet): class AdminTransmitterViewSet(ModelViewSet):
permission_classes = [IsAuthenticated, IsSuperAdmin] permission_classes = [IsAuthenticated, IsSuperAdmin]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
@ -1057,7 +1086,7 @@ class AdminTransmitterOpinionViewSet(ModelViewSet):
pagination_class = None pagination_class = None
def get_queryset(self): def get_queryset(self):
queryset = TransmitterOpinion.objects.all().select_related("status", "scholar")
queryset = TransmitterOpinion.objects.all().select_related("status", "scholar", "opinion", "opinion__status")
transmitter_id = self.request.query_params.get("transmitter_id") transmitter_id = self.request.query_params.get("transmitter_id")
if transmitter_id: if transmitter_id:
queryset = queryset.filter(transmitter_id=transmitter_id) queryset = queryset.filter(transmitter_id=transmitter_id)

Loading…
Cancel
Save