Browse Source

feat(hadis): add multi-reference endpoints and serializers for interpretations with scan images

master
Mohsen Taba 4 days ago
parent
commit
d3c075c7fb
  1. 158
      apps/hadis/serializers/serializers_admin.py
  2. 3
      apps/hadis/urls.py
  3. 20
      apps/hadis/views_admin.py

158
apps/hadis/serializers/serializers_admin.py

@ -1076,8 +1076,162 @@ class AdminHadisCorrectionSerializer(serializers.ModelSerializer):
return instance
class AdminInterpretationReferenceSerializer(serializers.ModelSerializer):
book_reference_detail = serializers.SerializerMethodField(read_only=True)
edition_detail = serializers.SerializerMethodField(read_only=True)
book_volume_detail = serializers.SerializerMethodField(read_only=True)
images = serializers.SerializerMethodField(read_only=True)
delete_image_ids = serializers.ListField(
child=serializers.IntegerField(),
required=False,
write_only=True
)
class Meta:
model = InterpretationReference
fields = [
"id",
"interpretation",
"book_reference",
"book_reference_detail",
"edition",
"edition_detail",
"book_volume",
"book_volume_detail",
"hadith_number",
"volume",
"pages",
"address",
"url",
"images",
"delete_image_ids",
]
def get_book_reference_detail(self, obj):
if obj.book_reference:
request = self.context.get("request")
author = obj.book_reference.author
first_ed = obj.book_reference.editions.first() if hasattr(obj.book_reference, "editions") else None
pub = getattr(obj.book_reference, "publisher", None)
if pub is None and first_ed:
pub = first_ed.publisher
if isinstance(pub, list):
pub = get_localized_text(pub, request)
year = getattr(obj.book_reference, "year_of_publication", None)
if not year and first_ed:
year = first_ed.year_of_publication
num_vols = getattr(obj.book_reference, "number_of_volumes", None)
if num_vols is None and first_ed:
num_vols = first_ed.number_of_volumes
return {
"id": obj.book_reference.id,
"title": get_localized_text(obj.book_reference.title, request),
"slug": obj.book_reference.slug,
"publisher": pub or "",
"year_of_publication": year or "",
"number_of_volumes": num_vols,
"has_editions": getattr(obj.book_reference, "has_editions", False),
"author": {
"id": author.id,
"name": get_localized_text(author.name, request),
"slug": author.slug
} if author else None
}
return None
def get_edition_detail(self, obj):
if obj.edition:
request = self.context.get("request")
pub = obj.edition.publisher
if isinstance(pub, list):
pub = get_localized_text(pub, request)
return {
"id": obj.edition.id,
"edition_number": obj.edition.edition_number,
"publisher": pub,
"year_of_publication": obj.edition.year_of_publication,
"number_of_volumes": obj.edition.number_of_volumes,
}
return None
def get_book_volume_detail(self, obj):
if obj.book_volume:
return {
"id": obj.book_volume.id,
"title": obj.book_volume.title,
}
return None
def get_images(self, obj):
request = self.context.get("request")
return [
{
"id": img.id,
"image": absolute_https_url(img.image.url, request) if request and img.image else (img.image.url if img.image else None),
"thumbnail": absolute_https_url(img.image.url, request) if request and img.image else (img.image.url if img.image else None),
"priority": img.priority,
}
for img in obj.images.all()
]
def to_internal_value(self, data):
import json
data = safe_copy_data(data)
book_ref = data.get("book_reference")
if book_ref in ("", "none", "null"):
data["book_reference"] = None
edition = data.get("edition")
if edition in ("", "none", "null"):
data["edition"] = None
book_vol = data.get("book_volume")
if book_vol in ("", "none", "null"):
data["book_volume"] = None
delete_ids = data.get("delete_image_ids")
if delete_ids:
if isinstance(delete_ids, str):
try:
data["delete_image_ids"] = json.loads(delete_ids)
except ValueError:
data["delete_image_ids"] = [int(x) for x in delete_ids.split(",") if x.strip().isdigit()]
elif isinstance(delete_ids, list):
parsed = []
for x in delete_ids:
if isinstance(x, str) and x.strip().isdigit():
parsed.append(int(x))
elif isinstance(x, int):
parsed.append(x)
data["delete_image_ids"] = parsed
return super().to_internal_value(data)
def create(self, validated_data):
delete_image_ids = validated_data.pop("delete_image_ids", [])
instance = super().create(validated_data)
self._handle_images(instance, delete_image_ids)
return instance
def update(self, instance, validated_data):
delete_image_ids = validated_data.pop("delete_image_ids", [])
instance = super().update(instance, validated_data)
self._handle_images(instance, delete_image_ids)
return instance
def _handle_images(self, instance, delete_image_ids):
request = self.context.get("request")
if delete_image_ids:
instance.images.filter(id__in=delete_image_ids).delete()
if request:
new_images = request.FILES.getlist("uploaded_images") or request.FILES.getlist("uploaded_images[]") or request.FILES.getlist("images")
for img in new_images:
InterpretationReferenceImage.objects.create(reference=instance, image=img)
class AdminHadisInterpretationSerializer(serializers.ModelSerializer):
category_detail = AdminHadisCategoryBriefSerializer(source="category", read_only=True)
references = AdminInterpretationReferenceSerializer(many=True, read_only=True)
# Writable relation fields
book_reference_id = serializers.PrimaryKeyRelatedField(
@ -1111,10 +1265,11 @@ class AdminHadisInterpretationSerializer(serializers.ModelSerializer):
"book_reference_id",
"address",
"delete_image_ids",
"references",
"created_at",
"updated_at",
]
read_only_fields = ["id", "created_at", "updated_at"]
read_only_fields = ["id", "references", "created_at", "updated_at"]
def to_internal_value(self, data):
import json
@ -1168,6 +1323,7 @@ class AdminHadisInterpretationSerializer(serializers.ModelSerializer):
}
for img in images
]
ret["references"] = AdminInterpretationReferenceSerializer(instance.references.all(), many=True, context=self.context).data
return ret
def create(self, validated_data):

3
apps/hadis/urls.py

@ -14,7 +14,7 @@ from .views.reference_v2 import BookReferenceV2DetailView, BookReferenceV2SyncVi
from .views.version import ContentReleaseSyncView, HadisDatabaseVersionView
from .views.info import HadisInfoView
from .views_admin import (
AdminHadisCategoryViewSet, AdminHadisViewSet, AdminHadisCorrectionViewSet, AdminCorrectionReferenceViewSet, AdminHadisReferenceViewSet, AdminHadisInterpretationViewSet, AdminHadisStatusViewSet, AdminHadisTagViewSet, AdminHadisCollectionViewSet,
AdminHadisCategoryViewSet, AdminHadisViewSet, AdminHadisCorrectionViewSet, AdminCorrectionReferenceViewSet, AdminHadisReferenceViewSet, AdminInterpretationReferenceViewSet, AdminHadisInterpretationViewSet, AdminHadisStatusViewSet, AdminHadisTagViewSet, AdminHadisCollectionViewSet,
AdminBookSubjectAreaViewSet, AdminBookTypeViewSet, AdminBookTagViewSet, AdminBookAuthorViewSet, AdminBookAttributeViewSet, AdminBookReferenceImageViewSet, AdminHadisReferenceImageViewSet, AdminBookReferenceDocumentViewSet, AdminBookReferenceViewSet,
AdminTransmitterViewSet, AdminTransmitterReliabilityViewSet, DovodiBookSubjectAreaViewSet, DovodiBookTypeViewSet,
DovodiNarratorLayerViewSet, DovodiTransmitterReliabilityViewSet, DovodiOpinionStatusViewSet,
@ -38,6 +38,7 @@ admin_router.register(r'corrections', AdminHadisCorrectionViewSet, basename='adm
admin_router.register(r'correction-references', AdminCorrectionReferenceViewSet, basename='admin-correction-references')
admin_router.register(r'hadis-references', AdminHadisReferenceViewSet, basename='admin-hadis-references')
admin_router.register(r'interpretations', AdminHadisInterpretationViewSet, basename='admin-hadis-interpretations')
admin_router.register(r'interpretation-references', AdminInterpretationReferenceViewSet, basename='admin-interpretation-references')
admin_router.register(r'statuses', AdminHadisStatusViewSet, basename='admin-hadis-statuses')
admin_router.register(r'tags', AdminHadisTagViewSet, basename='admin-hadis-tags')
admin_router.register(r'collections', AdminHadisCollectionViewSet, basename='admin-hadis-collections')

20
apps/hadis/views_admin.py

@ -13,7 +13,7 @@ from .models import (
Hadis, HadisCategory, HadisCollection, HadisInCollection, HadisCorrection, HadisInterpretation, HadisStatus, HadisTag, HadisSect, HadisTransmitter, HadisReference, ReferenceImage,
BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, BookTag, BookEdition, BookVolume,
Transmitters, TransmitterReliability, NarratorLayer, OpinionStatus, TransmitterOpinion, TransmitterOriginalText,
CorrectionReference,
CorrectionReference, InterpretationReference,
ContentRelease,
CategoryQuranVerse,
)
@ -24,6 +24,7 @@ from .serializers.serializers_admin import (
AdminHadisCategoryArchiveDetailSerializer,
AdminHadisCorrectionSerializer,
AdminCorrectionReferenceSerializer,
AdminInterpretationReferenceSerializer,
AdminHadisReferenceSerializer,
AdminHadisDetailSerializer,
AdminHadisInterpretationSerializer,
@ -484,6 +485,23 @@ class AdminHadisReferenceViewSet(ModelViewSet):
return qs.order_by("id")
class AdminInterpretationReferenceViewSet(ModelViewSet):
serializer_class = AdminInterpretationReferenceSerializer
permission_classes = [IsAuthenticated, IsSuperAdmin]
authentication_classes = [TokenAuthentication]
parser_classes = (MultiPartParser, FormParser, JSONParser)
pagination_class = OptionalPagination
def get_queryset(self):
qs = InterpretationReference.objects.all().select_related(
"book_reference__author", "edition", "book_volume"
).prefetch_related("images")
interpretation_id = self.request.query_params.get("interpretation_id") or self.request.query_params.get("interpretation")
if interpretation_id:
qs = qs.filter(interpretation_id=interpretation_id)
return qs.order_by("id")
class AdminHadisInterpretationViewSet(ModelViewSet):
serializer_class = AdminHadisInterpretationSerializer
permission_classes = [IsAuthenticated, IsSuperAdmin]

Loading…
Cancel
Save