Browse Source

feat(hadis): support multiple book references with scan images, volume details, and admin endpoints

master
Mohsen Taba 5 days ago
parent
commit
76575da481
  1. 29
      apps/hadis/migrations/0045_hadisreference_address_hadisreference_book_volume_and_more.py
  2. 17
      apps/hadis/models/hadis.py
  3. 203
      apps/hadis/serializers/hadis.py
  4. 312
      apps/hadis/serializers/serializers_admin.py
  5. 3
      apps/hadis/urls.py
  6. 4
      apps/hadis/views/hadis.py
  7. 18
      apps/hadis/views_admin.py

29
apps/hadis/migrations/0045_hadisreference_address_hadisreference_book_volume_and_more.py

@ -0,0 +1,29 @@
# Generated by Django 4.2.30 on 2026-10-06 10:04
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('hadis', '0044_alter_hadiscategory_description_and_more'),
]
operations = [
migrations.AddField(
model_name='hadisreference',
name='address',
field=models.TextField(blank=True, null=True, verbose_name='Address'),
),
migrations.AddField(
model_name='hadisreference',
name='book_volume',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='hadis_references', to='hadis.bookvolume', verbose_name='Volume Record'),
),
migrations.AddField(
model_name='hadisreference',
name='edition',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='hadis_references', to='hadis.bookedition', verbose_name='Edition'),
),
]

17
apps/hadis/models/hadis.py

@ -307,8 +307,25 @@ class HadisReference(models.Model):
verbose_name=_('book reference'), verbose_name=_('book reference'),
related_name='hadis_references' related_name='hadis_references'
) )
edition = models.ForeignKey(
'hadis.BookEdition',
on_delete=models.SET_NULL,
null=True,
blank=True,
verbose_name=_('Edition'),
related_name='hadis_references'
)
book_volume = models.ForeignKey(
'hadis.BookVolume',
on_delete=models.SET_NULL,
null=True,
blank=True,
verbose_name=_('Volume Record'),
related_name='hadis_references'
)
volume = models.CharField(max_length=100, null=True, blank=True) volume = models.CharField(max_length=100, null=True, blank=True)
pages = models.CharField(max_length=100, null=True, blank=True) pages = models.CharField(max_length=100, null=True, blank=True)
address = models.TextField(null=True, blank=True, verbose_name=_('Address'))
url = models.URLField(max_length=1000, null=True, blank=True) url = models.URLField(max_length=1000, null=True, blank=True)
hadith_number = models.CharField(max_length=100, null=True, blank=True, verbose_name=_('Hadith Number in Book')) hadith_number = models.CharField(max_length=100, null=True, blank=True, verbose_name=_('Hadith Number in Book'))

203
apps/hadis/serializers/hadis.py

@ -1036,33 +1036,181 @@ class HadisTransmitterListSerializer(serializers.ModelSerializer):
class ReferenceImageSerializer(serializers.ModelSerializer): class ReferenceImageSerializer(serializers.ModelSerializer):
"""Serializer for ReferenceImage""" """Serializer for ReferenceImage"""
thumbnail = serializers.SerializerMethodField() thumbnail = serializers.SerializerMethodField()
image = serializers.SerializerMethodField()
class Meta: class Meta:
model = ReferenceImage model = ReferenceImage
fields = ['id', 'thumbnail', 'priority']
fields = ['id', 'thumbnail', 'image', 'priority']
def get_thumbnail(self, obj): def get_thumbnail(self, obj):
"""Get thumbnail URL""" """Get thumbnail URL"""
if obj.thumbnail:
img = getattr(obj, 'thumbnail', None) or getattr(obj, 'image', None)
if img:
request = self.context.get('request') request = self.context.get('request')
if request: if request:
return absolute_https_url(obj.thumbnail.url, request)
return absolute_https_url(obj.thumbnail.url)
return absolute_https_url(img.url, request)
return absolute_https_url(img.url)
return None return None
def get_image(self, obj):
return self.get_thumbnail(obj)
class HadisReferenceSerializer(serializers.ModelSerializer): class HadisReferenceSerializer(serializers.ModelSerializer):
"""Serializer for HadisReference with book and images"""
"""Serializer for HadisReference with book, author, edition, volume, and images"""
book_title = serializers.SerializerMethodField() book_title = serializers.SerializerMethodField()
book_authors = serializers.SerializerMethodField() book_authors = serializers.SerializerMethodField()
book_description = serializers.SerializerMethodField() book_description = serializers.SerializerMethodField()
share_link = serializers.CharField(source='book_reference.share_link', read_only=True) share_link = serializers.CharField(source='book_reference.share_link', read_only=True)
edition = serializers.SerializerMethodField()
edition_info = serializers.SerializerMethodField()
volume_info = serializers.SerializerMethodField()
volume = serializers.SerializerMethodField()
pages = serializers.SerializerMethodField()
hadith_number = serializers.SerializerMethodField()
citation_summary = serializers.SerializerMethodField()
open_book_url = serializers.SerializerMethodField()
book = serializers.SerializerMethodField()
author = serializers.SerializerMethodField()
images = ReferenceImageSerializer(many=True, read_only=True)
images_count = serializers.SerializerMethodField()
class Meta: class Meta:
model = HadisReference model = HadisReference
fields = [ fields = [
'id', 'book_title', 'book_description','book_authors','share_link'
'id', 'book', 'author', 'book_title', 'book_description', 'book_authors', 'share_link',
'edition', 'edition_info', 'volume_info', 'volume', 'pages', 'hadith_number',
'address', 'url', 'open_book_url', 'citation_summary', 'images', 'images_count'
] ]
def get_edition_info(self, obj):
edition = obj.edition
if not edition and getattr(obj, "book_volume", None) and obj.book_volume.edition:
edition = obj.book_volume.edition
if not edition and getattr(obj, "book_reference", None) and hasattr(obj.book_reference, "editions"):
edition = obj.book_reference.editions.first()
if edition:
request = self.context.get("request")
pub = edition.publisher
if isinstance(pub, list):
pub = get_localized_text(pub, request)
return {
"id": edition.id,
"edition_number": edition.edition_number,
"publisher": pub or "",
"year_of_publication": edition.year_of_publication or "",
"number_of_volumes": edition.number_of_volumes,
}
return None
def get_volume_info(self, obj):
if obj.book_volume:
return {
"id": obj.book_volume.id,
"title": obj.book_volume.title
}
return None
def get_edition(self, obj):
return self.get_edition_info(obj)
def get_volume(self, obj):
if obj.volume and str(obj.volume).strip().lower() != "none":
return obj.volume
if obj.book_volume and obj.book_volume.title:
return obj.book_volume.title
return None
def get_pages(self, obj):
if obj.pages and str(obj.pages).strip().lower() != "none":
return obj.pages
return None
def get_hadith_number(self, obj):
if obj.hadith_number and str(obj.hadith_number).strip().lower() != "none":
return obj.hadith_number
return None
def get_citation_summary(self, obj):
parts = []
vol = self.get_volume(obj)
pg = self.get_pages(obj)
num = self.get_hadith_number(obj)
if vol:
vol_str = str(vol).strip()
if vol_str.startswith("جلد"):
parts.append(vol_str)
else:
parts.append(f"جلد {vol_str}")
if pg:
pg_str = str(pg).strip()
if pg_str.startswith("ص") or pg_str.startswith("صفحه"):
parts.append(pg_str)
else:
parts.append(f"صفحه {pg_str}")
if num:
num_str = str(num).strip()
if num_str.startswith("ح") or num_str.startswith("حدیث") or num_str.startswith("شماره"):
parts.append(num_str)
else:
parts.append(f"شماره حدیث {num_str}")
return " • ".join(parts) if parts else ""
def get_open_book_url(self, obj):
request = self.context.get('request')
if obj.book_volume and obj.book_volume.file:
return absolute_https_url(obj.book_volume.file.url, request) if request else absolute_https_url(obj.book_volume.file.url)
return obj.url or None
def get_book(self, obj):
if obj.book_reference:
request = self.context.get('request')
first_ed = obj.edition
if not first_ed and getattr(obj, "book_volume", None) and obj.book_volume.edition:
first_ed = obj.book_volume.edition
if not first_ed and hasattr(obj.book_reference, "editions"):
first_ed = obj.book_reference.editions.first()
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,
'slug': obj.book_reference.slug,
'title': get_localized_text(obj.book_reference.title, request) if isinstance(obj.book_reference.title, list) else obj.book_reference.title,
'publisher': pub or '',
'year_of_publication': year or '',
'number_of_volumes': num_vols,
}
return None
def get_author(self, obj):
if obj.book_reference and obj.book_reference.author:
author = obj.book_reference.author
request = self.context.get('request')
return {
'id': author.id,
'slug': author.slug,
'name': get_localized_text(author.name, request) if isinstance(author.name, list) else author.name
}
return None
def get_images_count(self, obj):
if hasattr(obj, '_prefetched_objects_cache') and 'images' in obj._prefetched_objects_cache:
return len(obj.images.all())
return obj.images.count()
# def get_type_name(self, obj): # def get_type_name(self, obj):
# """Get localized type name from book_reference.type""" # """Get localized type name from book_reference.type"""
# if obj.book_reference and obj.book_reference.type: # if obj.book_reference and obj.book_reference.type:
@ -1648,6 +1796,32 @@ class DetailedOriginalTextReferenceSerializer(BaseDetailedReferenceSerializer):
fields = ['id', 'book_title', 'book_authors', 'edition_info', 'volume_info', 'volume', 'pages', 'address', 'url', 'images'] fields = ['id', 'book_title', 'book_authors', 'edition_info', 'volume_info', 'volume', 'pages', 'address', 'url', 'images']
class DetailedHadisReferenceSerializer(DetailedCorrectionReferenceSerializer):
images = ReferenceImageSerializer(many=True, read_only=True)
class Meta:
model = HadisReference
fields = [
'id',
'book',
'author',
'edition',
'volume_info',
'hadith_number',
'volume',
'pages',
'address',
'url',
'open_book_url',
'citation_summary',
'images',
'images_count',
'book_title',
'book_authors',
'edition_info',
]
# --- سریالایزرهای اصلی جزئیات (Detail Serializers) --- # --- سریالایزرهای اصلی جزئیات (Detail Serializers) ---
class HadisCorrectionDetailSerializer(serializers.ModelSerializer): class HadisCorrectionDetailSerializer(serializers.ModelSerializer):
@ -1779,7 +1953,7 @@ class TransmitterOriginalTextDetailSerializer(serializers.ModelSerializer):
class HadisSourceDetailsSerializer(serializers.ModelSerializer): class HadisSourceDetailsSerializer(serializers.ModelSerializer):
""" """
Lightweight serializer for Hadis Source Details (Address, Links, Images).
Lightweight serializer for Hadis Source Details (Address, Links, Images, Reference).
Used on-demand when opening source detail modals in web and mobile clients. Used on-demand when opening source detail modals in web and mobile clients.
""" """
title = LocalizedField() title = LocalizedField()
@ -1788,12 +1962,15 @@ class HadisSourceDetailsSerializer(serializers.ModelSerializer):
address = serializers.SerializerMethodField() address = serializers.SerializerMethodField()
links = serializers.SerializerMethodField() links = serializers.SerializerMethodField()
images = serializers.SerializerMethodField() images = serializers.SerializerMethodField()
reference = serializers.SerializerMethodField()
references = serializers.SerializerMethodField()
class Meta: class Meta:
model = Hadis model = Hadis
fields = [ fields = [
'id', 'slug', 'title', 'narrator', 'source_type', 'id', 'slug', 'title', 'narrator', 'source_type',
'address', 'links', 'images', 'share_link'
'address', 'links', 'images', 'share_link',
'reference', 'references'
] ]
def get_source_type(self, obj): def get_source_type(self, obj):
@ -1835,3 +2012,13 @@ class HadisSourceDetailsSerializer(serializers.ModelSerializer):
}) })
return images_list return images_list
def get_reference(self, obj):
ref = obj.references.first()
if ref:
return DetailedHadisReferenceSerializer(ref, context=self.context).data
return None
def get_references(self, obj):
refs = obj.references.all()
return DetailedHadisReferenceSerializer(refs, many=True, context=self.context).data

312
apps/hadis/serializers/serializers_admin.py

@ -245,6 +245,174 @@ class AdminHadisCollectionSerializer(serializers.ModelSerializer):
return super().update(instance, validated_data) return super().update(instance, validated_data)
class AdminHadisReferenceSerializer(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 = HadisReference
fields = [
"id",
"hadis",
"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) if isinstance(obj.book_reference.title, list) else obj.book_reference.title,
"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) if isinstance(author.name, list) else author.name,
"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 or "",
"year_of_publication": obj.edition.year_of_publication or "",
"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,
"reference_id": obj.id,
"hadis_id": obj.hadis_id,
"thumbnail": absolute_https_url(img.thumbnail.url, request) if request and img.thumbnail else (img.thumbnail.url if img.thumbnail else None),
"image": absolute_https_url(img.thumbnail.url, request) if request and img.thumbnail else (img.thumbnail.url if img.thumbnail else None),
"priority": img.priority,
}
for img in obj.images.all().order_by("priority", "id")
]
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")
or request.FILES.getlist("images[]")
)
single_img = request.FILES.get("image") or request.FILES.get("thumbnail")
if single_img and not new_images:
new_images = [single_img]
last_img = instance.images.order_by("-priority").first()
current_priority = (last_img.priority + 1) if last_img else 1
for img in new_images:
ReferenceImage.objects.create(reference=instance, thumbnail=img, priority=current_priority)
current_priority += 1
class AdminHadisDetailSerializer(serializers.ModelSerializer): class AdminHadisDetailSerializer(serializers.ModelSerializer):
category_detail = AdminHadisCategorySerializer(source="category", read_only=True) category_detail = AdminHadisCategorySerializer(source="category", read_only=True)
hadis_status_detail = AdminHadisStatusSerializer(source="hadis_status", read_only=True) hadis_status_detail = AdminHadisStatusSerializer(source="hadis_status", read_only=True)
@ -279,6 +447,36 @@ class AdminHadisDetailSerializer(serializers.ModelSerializer):
write_only=True, write_only=True,
allow_null=True, allow_null=True,
) )
edition_id = serializers.PrimaryKeyRelatedField(
queryset=BookEdition.objects.all(),
required=False,
write_only=True,
allow_null=True,
)
book_volume_id = serializers.PrimaryKeyRelatedField(
queryset=BookVolume.objects.all(),
required=False,
write_only=True,
allow_null=True,
)
volume = serializers.CharField(
required=False,
write_only=True,
allow_null=True,
allow_blank=True,
)
pages = serializers.CharField(
required=False,
write_only=True,
allow_null=True,
allow_blank=True,
)
hadith_number = serializers.CharField(
required=False,
write_only=True,
allow_null=True,
allow_blank=True,
)
bookmark_count = serializers.SerializerMethodField() bookmark_count = serializers.SerializerMethodField()
@ -325,6 +523,11 @@ class AdminHadisDetailSerializer(serializers.ModelSerializer):
"collections", "collections",
"collections_detail", "collections_detail",
"book_reference_id", "book_reference_id",
"edition_id",
"book_volume_id",
"volume",
"pages",
"hadith_number",
"share_link", "share_link",
"explanation", "explanation",
"bookmark_count", "bookmark_count",
@ -336,22 +539,75 @@ class AdminHadisDetailSerializer(serializers.ModelSerializer):
def to_representation(self, instance): def to_representation(self, instance):
ret = super().to_representation(instance) ret = super().to_representation(instance)
request = self.context.get("request")
refs = list(instance.references.all()) refs = list(instance.references.all())
ref = refs[0] if refs else None ref = refs[0] if refs else None
ret["book_reference"] = ref.book_reference_id if ref else None ret["book_reference"] = ref.book_reference_id if ref else None
ret["edition"] = ref.edition_id if ref else None
ret["book_volume"] = ref.book_volume_id if ref else None
ret["volume"] = ref.volume if ref else None
ret["pages"] = ref.pages if ref else None
ret["hadith_number"] = ref.hadith_number if ref else None
if ref and ref.book_reference: if ref and ref.book_reference:
author = ref.book_reference.author
first_ed = ref.book_reference.editions.first() if hasattr(ref.book_reference, "editions") else None
pub = getattr(ref.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(ref.book_reference, "year_of_publication", None)
if not year and first_ed:
year = first_ed.year_of_publication
num_vols = getattr(ref.book_reference, "number_of_volumes", None)
if num_vols is None and first_ed:
num_vols = first_ed.number_of_volumes
ret["book_reference_detail"] = { ret["book_reference_detail"] = {
"id": ref.book_reference.id, "id": ref.book_reference.id,
"title": ref.book_reference.title,
"title": get_localized_text(ref.book_reference.title, request) if isinstance(ref.book_reference.title, list) else ref.book_reference.title,
"slug": ref.book_reference.slug, "slug": ref.book_reference.slug,
"publisher": pub or "",
"year_of_publication": year or "",
"number_of_volumes": num_vols,
"has_editions": getattr(ref.book_reference, "has_editions", False),
"author": {
"id": author.id,
"name": get_localized_text(author.name, request) if isinstance(author.name, list) else author.name,
"slug": author.slug
} if author else None
} }
else: else:
ret["book_reference_detail"] = None ret["book_reference_detail"] = None
if ref and ref.edition:
ed = ref.edition
pub = ed.publisher
if isinstance(pub, list):
pub = get_localized_text(pub, request)
ret["edition_detail"] = {
"id": ed.id,
"edition_number": ed.edition_number,
"publisher": pub or "",
"year_of_publication": ed.year_of_publication or "",
"number_of_volumes": ed.number_of_volumes,
}
else:
ret["edition_detail"] = None
if ref and ref.book_volume:
ret["book_volume_detail"] = {
"id": ref.book_volume.id,
"title": ref.book_volume.title,
}
else:
ret["book_volume_detail"] = None
ref_images = [] ref_images = []
for r in refs: for r in refs:
for img in r.images.all().order_by("priority", "id"): for img in r.images.all().order_by("priority", "id"):
url = absolute_https_url(img.thumbnail.url, self.context.get("request")) if img.thumbnail else None
url = absolute_https_url(img.thumbnail.url, request) if img.thumbnail else None
ref_images.append({ ref_images.append({
"id": img.id, "id": img.id,
"reference_id": r.id, "reference_id": r.id,
@ -361,6 +617,7 @@ class AdminHadisDetailSerializer(serializers.ModelSerializer):
"priority": img.priority, "priority": img.priority,
}) })
ret["reference_images"] = ref_images ret["reference_images"] = ref_images
ret["references"] = AdminHadisReferenceSerializer(instance.references.all().order_by("id"), many=True, context=self.context).data
return ret return ret
def get_bookmark_count(self, obj): def get_bookmark_count(self, obj):
@ -380,6 +637,11 @@ class AdminHadisDetailSerializer(serializers.ModelSerializer):
def create(self, validated_data): def create(self, validated_data):
book_reference = validated_data.pop("book_reference_id", None) book_reference = validated_data.pop("book_reference_id", None)
edition = validated_data.pop("edition_id", None)
book_volume = validated_data.pop("book_volume_id", None)
volume = validated_data.pop("volume", None)
pages = validated_data.pop("pages", None)
hadith_number = validated_data.pop("hadith_number", None)
tags = validated_data.pop("tags", []) tags = validated_data.pop("tags", [])
collections = validated_data.pop("collection_items", []) collections = validated_data.pop("collection_items", [])
hadis = super().create(validated_data) hadis = super().create(validated_data)
@ -388,13 +650,32 @@ class AdminHadisDetailSerializer(serializers.ModelSerializer):
if collections: if collections:
for idx, col in enumerate(collections): for idx, col in enumerate(collections):
HadisInCollection.objects.create(hadis=hadis, collection=col, order=idx) HadisInCollection.objects.create(hadis=hadis, collection=col, order=idx)
if book_reference:
HadisReference.objects.create(hadis=hadis, book_reference=book_reference)
if book_reference or edition or book_volume or volume or pages or hadith_number:
HadisReference.objects.create(
hadis=hadis,
book_reference=book_reference,
edition=edition,
book_volume=book_volume,
volume=volume or "",
pages=pages or "",
hadith_number=hadith_number or ""
)
return hadis return hadis
def update(self, instance, validated_data): def update(self, instance, validated_data):
book_reference_provided = "book_reference_id" in validated_data book_reference_provided = "book_reference_id" in validated_data
book_reference = validated_data.pop("book_reference_id", None) book_reference = validated_data.pop("book_reference_id", None)
edition_provided = "edition_id" in validated_data
edition = validated_data.pop("edition_id", None)
book_volume_provided = "book_volume_id" in validated_data
book_volume = validated_data.pop("book_volume_id", None)
volume_provided = "volume" in validated_data
volume = validated_data.pop("volume", None)
pages_provided = "pages" in validated_data
pages = validated_data.pop("pages", None)
hadith_number_provided = "hadith_number" in validated_data
hadith_number = validated_data.pop("hadith_number", None)
tags = validated_data.pop("tags", None) tags = validated_data.pop("tags", None)
collections = validated_data.pop("collection_items", None) collections = validated_data.pop("collection_items", None)
hadis = super().update(instance, validated_data) hadis = super().update(instance, validated_data)
@ -404,13 +685,30 @@ class AdminHadisDetailSerializer(serializers.ModelSerializer):
instance.collection_items.all().delete() instance.collection_items.all().delete()
for idx, col in enumerate(collections): for idx, col in enumerate(collections):
HadisInCollection.objects.create(hadis=hadis, collection=col, order=idx) HadisInCollection.objects.create(hadis=hadis, collection=col, order=idx)
if book_reference_provided:
any_ref_provided = (
book_reference_provided or edition_provided or book_volume_provided or
volume_provided or pages_provided or hadith_number_provided
)
if any_ref_provided:
ref = instance.references.first() ref = instance.references.first()
if not ref:
if book_reference or edition or book_volume or volume or pages or hadith_number:
ref = HadisReference.objects.create(hadis=hadis)
if ref: if ref:
if book_reference_provided:
ref.book_reference = book_reference ref.book_reference = book_reference
if edition_provided:
ref.edition = edition
if book_volume_provided:
ref.book_volume = book_volume
if volume_provided:
ref.volume = volume or ""
if pages_provided:
ref.pages = pages or ""
if hadith_number_provided:
ref.hadith_number = hadith_number or ""
ref.save() ref.save()
elif book_reference:
HadisReference.objects.create(hadis=hadis, book_reference=book_reference)
return hadis return hadis

3
apps/hadis/urls.py

@ -14,7 +14,7 @@ from .views.reference_v2 import BookReferenceV2DetailView, BookReferenceV2SyncVi
from .views.version import ContentReleaseSyncView, HadisDatabaseVersionView from .views.version import ContentReleaseSyncView, HadisDatabaseVersionView
from .views.info import HadisInfoView from .views.info import HadisInfoView
from .views_admin import ( from .views_admin import (
AdminHadisCategoryViewSet, AdminHadisViewSet, AdminHadisCorrectionViewSet, AdminCorrectionReferenceViewSet, AdminHadisInterpretationViewSet, AdminHadisStatusViewSet, AdminHadisTagViewSet, AdminHadisCollectionViewSet,
AdminHadisCategoryViewSet, AdminHadisViewSet, AdminHadisCorrectionViewSet, AdminCorrectionReferenceViewSet, AdminHadisReferenceViewSet, 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,
@ -36,6 +36,7 @@ admin_router.register(r'dovodi-sects', DovodiHadisSectViewSet, basename='dovodi-
admin_router.register(r'dovodi-categories', DovodiHadisCategoryViewSet, basename='dovodi-hadis-categories') admin_router.register(r'dovodi-categories', DovodiHadisCategoryViewSet, basename='dovodi-hadis-categories')
admin_router.register(r'corrections', AdminHadisCorrectionViewSet, basename='admin-hadis-corrections') admin_router.register(r'corrections', AdminHadisCorrectionViewSet, basename='admin-hadis-corrections')
admin_router.register(r'correction-references', AdminCorrectionReferenceViewSet, basename='admin-correction-references') 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'interpretations', AdminHadisInterpretationViewSet, basename='admin-hadis-interpretations')
admin_router.register(r'statuses', AdminHadisStatusViewSet, basename='admin-hadis-statuses') admin_router.register(r'statuses', AdminHadisStatusViewSet, basename='admin-hadis-statuses')
admin_router.register(r'tags', AdminHadisTagViewSet, basename='admin-hadis-tags') admin_router.register(r'tags', AdminHadisTagViewSet, basename='admin-hadis-tags')

4
apps/hadis/views/hadis.py

@ -1323,7 +1323,9 @@ class HadisSourceDetailsView(RetrieveAPIView):
).prefetch_related( ).prefetch_related(
Prefetch( Prefetch(
'references', 'references',
queryset=HadisReference.objects.prefetch_related(
queryset=HadisReference.objects.select_related(
'book_reference', 'book_reference__author', 'edition', 'book_volume'
).prefetch_related(
Prefetch('images', queryset=ReferenceImage.objects.order_by('priority')) Prefetch('images', queryset=ReferenceImage.objects.order_by('priority'))
) )
) )

18
apps/hadis/views_admin.py

@ -24,6 +24,7 @@ from .serializers.serializers_admin import (
AdminHadisCategoryArchiveDetailSerializer, AdminHadisCategoryArchiveDetailSerializer,
AdminHadisCorrectionSerializer, AdminHadisCorrectionSerializer,
AdminCorrectionReferenceSerializer, AdminCorrectionReferenceSerializer,
AdminHadisReferenceSerializer,
AdminHadisDetailSerializer, AdminHadisDetailSerializer,
AdminHadisInterpretationSerializer, AdminHadisInterpretationSerializer,
AdminHadisCollectionSerializer, AdminHadisCollectionSerializer,
@ -466,6 +467,23 @@ class AdminCorrectionReferenceViewSet(ModelViewSet):
return qs.order_by("id") return qs.order_by("id")
class AdminHadisReferenceViewSet(ModelViewSet):
serializer_class = AdminHadisReferenceSerializer
permission_classes = [IsAuthenticated, IsSuperAdmin]
authentication_classes = [TokenAuthentication]
parser_classes = (MultiPartParser, FormParser, JSONParser)
pagination_class = OptionalPagination
def get_queryset(self):
qs = HadisReference.objects.all().select_related(
"book_reference__author", "edition", "book_volume"
).prefetch_related("images")
hadis_id = self.request.query_params.get("hadis_id")
if hadis_id:
qs = qs.filter(hadis_id=hadis_id)
return qs.order_by("id")
class AdminHadisInterpretationViewSet(ModelViewSet): class AdminHadisInterpretationViewSet(ModelViewSet):
serializer_class = AdminHadisInterpretationSerializer serializer_class = AdminHadisInterpretationSerializer
permission_classes = [IsAuthenticated, IsSuperAdmin] permission_classes = [IsAuthenticated, IsSuperAdmin]

Loading…
Cancel
Save