Browse Source

feat(references): add volume unique images and source/edition single tag system

master
Mohsen Taba 3 weeks ago
parent
commit
1f3a13861b
  1. 4
      apps/hadis/admin/reference.py
  2. 37
      apps/hadis/migrations/0037_remove_bookedition_tags_remove_bookreference_tags_and_more.py
  3. 23
      apps/hadis/models/reference.py
  4. 24
      apps/hadis/serializers/reference_v2.py
  5. 47
      apps/hadis/serializers/serializers_admin.py
  6. 13
      apps/hadis/urls.py
  7. 1914
      apps/hadis/views/hadis.py
  8. 56
      apps/hadis/views/reference.py
  9. 2
      apps/hadis/views/reference_v2.py
  10. 19
      apps/hadis/views_admin.py

4
apps/hadis/admin/reference.py

@ -487,11 +487,11 @@ class BookReferenceAdmin(ModelAdmin):
inlines = [BookReferenceImageInline, BookAttributeInline] inlines = [BookReferenceImageInline, BookAttributeInline]
# Use filter_horizontal for ManyToMany fields to make selection easier # Use filter_horizontal for ManyToMany fields to make selection easier
filter_horizontal = ('subject_area', 'tags')
filter_horizontal = ('subject_area',)
fieldsets = ( fieldsets = (
(_('Basic Info'), { (_('Basic Info'), {
'fields': ('title', 'description', 'slug', 'language', 'tags', 'type', 'author')
'fields': ('title', 'description', 'slug', 'language', 'tag', 'type', 'author')
}), }),
(_('Publication Info'), { (_('Publication Info'), {
'fields': ('number_page',) 'fields': ('number_page',)

37
apps/hadis/migrations/0037_remove_bookedition_tags_remove_bookreference_tags_and_more.py

@ -0,0 +1,37 @@
# Generated by Django 4.2.30 on 2026-08-29 17:44
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('hadis', '0036_alter_narratorlayer_options_narratorlayer_hadis_and_more'),
]
operations = [
migrations.RemoveField(
model_name='bookedition',
name='tags',
),
migrations.RemoveField(
model_name='bookreference',
name='tags',
),
migrations.AddField(
model_name='bookedition',
name='tag',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='book_editions', to='hadis.booktag', verbose_name='Tag'),
),
migrations.AddField(
model_name='bookreference',
name='tag',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='book_references', to='hadis.booktag', verbose_name='Tag'),
),
migrations.AddField(
model_name='bookvolume',
name='image',
field=models.ImageField(blank=True, null=True, upload_to='hadis/volume_images/', verbose_name='Image'),
),
]

23
apps/hadis/models/reference.py

@ -101,11 +101,13 @@ class BookReference(LowercaseSlugMixin, models.Model):
verbose_name=_('Subject Area'), verbose_name=_('Subject Area'),
blank=True blank=True
) )
tags = models.ManyToManyField(
tag = models.ForeignKey(
'BookTag', 'BookTag',
verbose_name=_('Tags'),
on_delete=models.SET_NULL,
null=True,
blank=True, blank=True,
related_name='book_references'
related_name='book_references',
verbose_name=_('Tag')
) )
type = models.ForeignKey('BookType', on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Type')) type = models.ForeignKey('BookType', on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Type'))
author = models.ForeignKey( author = models.ForeignKey(
@ -215,7 +217,14 @@ class BookEdition(models.Model):
source_url = models.URLField(max_length=1000, null=True, blank=True, verbose_name=_('Online Source URL')) source_url = models.URLField(max_length=1000, null=True, blank=True, verbose_name=_('Online Source URL'))
isbn = models.CharField(max_length=100, verbose_name=_('ISBN'), blank=True, null=True) isbn = models.CharField(max_length=100, verbose_name=_('ISBN'), blank=True, null=True)
notes = models.JSONField(default=list, blank=True, verbose_name=_('Notes')) notes = models.JSONField(default=list, blank=True, verbose_name=_('Notes'))
tags = models.JSONField(default=list, blank=True, verbose_name=_('Tags'))
tag = models.ForeignKey(
'BookTag',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='book_editions',
verbose_name=_('Tag')
)
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'))
@ -235,6 +244,12 @@ class BookVolume(models.Model):
book_reference = models.ForeignKey(BookReference, on_delete=models.CASCADE, related_name='volumes', verbose_name=_('book reference')) book_reference = models.ForeignKey(BookReference, on_delete=models.CASCADE, related_name='volumes', verbose_name=_('book reference'))
edition = models.ForeignKey(BookEdition, on_delete=models.CASCADE, related_name='volumes', verbose_name=_('edition'), null=True, blank=True) edition = models.ForeignKey(BookEdition, on_delete=models.CASCADE, related_name='volumes', verbose_name=_('edition'), null=True, blank=True)
title = models.CharField(max_length=255, verbose_name=_('Title'), help_text=_('e.g., Volume 1'), blank=True, null=True) title = models.CharField(max_length=255, verbose_name=_('Title'), help_text=_('e.g., Volume 1'), blank=True, null=True)
image = models.ImageField(
upload_to='hadis/volume_images/',
null=True,
blank=True,
verbose_name=_('Image')
)
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'))

24
apps/hadis/serializers/reference_v2.py

@ -36,13 +36,13 @@ class BookEditorV2Serializer(serializers.ModelSerializer):
class BookReferenceV2ListSerializer(serializers.ModelSerializer): class BookReferenceV2ListSerializer(serializers.ModelSerializer):
title = LocalizedField() title = LocalizedField()
authors = serializers.SerializerMethodField() authors = serializers.SerializerMethodField()
tags = BookTagV2Serializer(many=True, read_only=True)
tag = BookTagV2Serializer(read_only=True)
number_of_volumes = serializers.SerializerMethodField() number_of_volumes = serializers.SerializerMethodField()
image = serializers.SerializerMethodField() image = serializers.SerializerMethodField()
class Meta: class Meta:
model = BookReference model = BookReference
fields = ['id', 'slug', 'title', 'authors', 'number_of_volumes', 'tags', 'image']
fields = ['id', 'slug', 'title', 'authors', 'number_of_volumes', 'tag', 'image']
def get_authors(self, obj): def get_authors(self, obj):
if obj.author: if obj.author:
@ -53,8 +53,18 @@ class BookReferenceV2ListSerializer(serializers.ModelSerializer):
return obj.volumes.count() return obj.volumes.count()
def get_image(self, obj): def get_image(self, obj):
if hasattr(obj, 'thumbnail') and obj.thumbnail:
request = self.context.get('request')
if request:
return absolute_https_url(obj.thumbnail.url, request)
return absolute_https_url(obj.thumbnail.url)
first_volume = obj.volumes.first() first_volume = obj.volumes.first()
if first_volume: if first_volume:
if first_volume.image:
request = self.context.get('request')
if request:
return absolute_https_url(first_volume.image.url, request)
return absolute_https_url(first_volume.image.url)
first_image = first_volume.images.order_by('order').first() first_image = first_volume.images.order_by('order').first()
if first_image and first_image.image: if first_image and first_image.image:
request = self.context.get('request') request = self.context.get('request')
@ -66,7 +76,7 @@ class BookReferenceV2ListSerializer(serializers.ModelSerializer):
class BookEditionV2Serializer(serializers.ModelSerializer): class BookEditionV2Serializer(serializers.ModelSerializer):
publisher = LocalizedField() publisher = LocalizedField()
notes = LocalizedField() notes = LocalizedField()
tags = LocalizedField()
tag = BookTagV2Serializer(read_only=True)
publication_place = serializers.SerializerMethodField() publication_place = serializers.SerializerMethodField()
researchers = BookResearcherV2Serializer(many=True, read_only=True) researchers = BookResearcherV2Serializer(many=True, read_only=True)
editors = BookEditorV2Serializer(many=True, read_only=True) editors = BookEditorV2Serializer(many=True, read_only=True)
@ -75,7 +85,7 @@ class BookEditionV2Serializer(serializers.ModelSerializer):
model = BookEdition model = BookEdition
fields = [ fields = [
'id', 'publisher', 'publication_place', 'edition_number', 'id', 'publisher', 'publication_place', 'edition_number',
'year_of_publication', 'number_of_volumes', 'notes', 'source_url', 'tags',
'year_of_publication', 'number_of_volumes', 'notes', 'source_url', 'tag',
'researchers', 'editors' 'researchers', 'editors'
] ]
@ -96,9 +106,13 @@ class BookVolumeV2Serializer(serializers.ModelSerializer):
fields = ['id', 'title', 'image'] fields = ['id', 'title', 'image']
def get_image(self, obj): def get_image(self, obj):
request = self.context.get('request')
if obj.image:
if request:
return absolute_https_url(obj.image.url, request)
return absolute_https_url(obj.image.url)
first_image = obj.images.order_by('order').first() first_image = obj.images.order_by('order').first()
if first_image and first_image.image: if first_image and first_image.image:
request = self.context.get('request')
if request: if request:
return absolute_https_url(first_image.image.url, request) return absolute_https_url(first_image.image.url, request)
return absolute_https_url(first_image.image.url) return absolute_https_url(first_image.image.url)

47
apps/hadis/serializers/serializers_admin.py

@ -7,7 +7,7 @@ from utils.image_compression import maybe_compress_uploaded_file
from utils import absolute_https_url from utils import absolute_https_url
from ..models import ( from ..models import (
Hadis, HadisCategory, HadisStatus, HadisTag, HadisCorrection, HadisInterpretation, HadisCollection, HadisSect, HadisInCollection, HadisTransmitter, HadisReference, Hadis, HadisCategory, HadisStatus, HadisTag, HadisCorrection, HadisInterpretation, HadisCollection, HadisSect, HadisInCollection, HadisTransmitter, HadisReference,
BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, 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, TransmitterOpinion, TransmitterOriginalText,
CorrectionReference, CorrectionReferenceImage, InterpretationReference, InterpretationReferenceImage, CorrectionReference, CorrectionReferenceImage, InterpretationReference, InterpretationReferenceImage,
OriginalTextReference, OriginalTextReferenceImage OriginalTextReference, OriginalTextReferenceImage
@ -1179,9 +1179,19 @@ class AdminBookReferenceDocumentSerializer(serializers.ModelSerializer):
return obj.book_volume.title if getattr(obj, 'book_volume', None) else "" return obj.book_volume.title if getattr(obj, 'book_volume', None) else ""
class AdminBookTagSerializer(serializers.ModelSerializer):
title = serializers.JSONField(default=list)
class Meta:
model = BookTag
fields = ["id", "title", "created_at", "updated_at"]
class AdminBookReferenceListSerializer(serializers.ModelSerializer): class AdminBookReferenceListSerializer(serializers.ModelSerializer):
author_id = serializers.IntegerField(source="author.id", read_only=True, allow_null=True) author_id = serializers.IntegerField(source="author.id", read_only=True, allow_null=True)
author_name = serializers.JSONField(source="author.name", read_only=True, allow_null=True) author_name = serializers.JSONField(source="author.name", read_only=True, allow_null=True)
tag_id = serializers.IntegerField(source="tag.id", read_only=True, allow_null=True)
tag_detail = AdminBookTagSerializer(source="tag", read_only=True)
volume = serializers.SerializerMethodField() volume = serializers.SerializerMethodField()
publisher = serializers.SerializerMethodField() publisher = serializers.SerializerMethodField()
year_of_publication = serializers.SerializerMethodField() year_of_publication = serializers.SerializerMethodField()
@ -1195,6 +1205,8 @@ class AdminBookReferenceListSerializer(serializers.ModelSerializer):
"has_editions", "has_editions",
"author_id", "author_id",
"author_name", "author_name",
"tag_id",
"tag_detail",
"volume", "volume",
"publisher", "publisher",
"year_of_publication", "year_of_publication",
@ -1219,6 +1231,7 @@ class AdminBookReferenceDetailSerializer(serializers.ModelSerializer):
subject_area_detail = AdminBookSubjectAreaSerializer(source="subject_area", many=True, read_only=True) subject_area_detail = AdminBookSubjectAreaSerializer(source="subject_area", many=True, read_only=True)
type_detail = AdminBookTypeSerializer(source="type", read_only=True) type_detail = AdminBookTypeSerializer(source="type", read_only=True)
author_detail = AdminBookAuthorSerializer(source="author", read_only=True) author_detail = AdminBookAuthorSerializer(source="author", read_only=True)
tag_detail = AdminBookTagSerializer(source="tag", read_only=True)
subject_area = serializers.PrimaryKeyRelatedField( subject_area = serializers.PrimaryKeyRelatedField(
queryset=BookSubjectArea.objects.all(), queryset=BookSubjectArea.objects.all(),
@ -1235,6 +1248,11 @@ class AdminBookReferenceDetailSerializer(serializers.ModelSerializer):
required=False, required=False,
allow_null=True, allow_null=True,
) )
tag = serializers.PrimaryKeyRelatedField(
queryset=BookTag.objects.all(),
required=False,
allow_null=True,
)
source_url = serializers.SerializerMethodField() source_url = serializers.SerializerMethodField()
isbn = serializers.SerializerMethodField() isbn = serializers.SerializerMethodField()
@ -1303,6 +1321,8 @@ class AdminBookReferenceDetailSerializer(serializers.ModelSerializer):
"subject_area_detail", "subject_area_detail",
"type", "type",
"type_detail", "type_detail",
"tag",
"tag_detail",
"order", "order",
"city_of_publication", "city_of_publication",
"country_of_publication", "country_of_publication",
@ -1548,6 +1568,8 @@ class AdminTransmitterOriginalTextSerializer(serializers.ModelSerializer):
class AdminBookVolumeSerializer(serializers.ModelSerializer): class AdminBookVolumeSerializer(serializers.ModelSerializer):
remove_image = serializers.BooleanField(write_only=True, required=False, default=False)
class Meta: class Meta:
model = BookVolume model = BookVolume
fields = [ fields = [
@ -1555,10 +1577,23 @@ class AdminBookVolumeSerializer(serializers.ModelSerializer):
"book_reference", "book_reference",
"edition", "edition",
"title", "title",
"image",
"remove_image",
"created_at", "created_at",
"updated_at", "updated_at",
] ]
def create(self, validated_data):
validated_data.pop("remove_image", False)
return super().create(validated_data)
def update(self, instance, validated_data):
remove_image = validated_data.pop("remove_image", False)
if remove_image and instance.image:
instance.image.delete(save=False)
instance.image = None
return super().update(instance, validated_data)
class AdminBookResearcherSerializer(serializers.ModelSerializer): class AdminBookResearcherSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False) id = serializers.IntegerField(required=False)
@ -1583,7 +1618,12 @@ class AdminBookEditionSerializer(serializers.ModelSerializer):
city_of_publication = serializers.JSONField(required=False, default=list) city_of_publication = serializers.JSONField(required=False, default=list)
country_of_publication = serializers.JSONField(required=False, default=list) country_of_publication = serializers.JSONField(required=False, default=list)
notes = serializers.JSONField(required=False, default=list) notes = serializers.JSONField(required=False, default=list)
tags = serializers.JSONField(required=False, default=list)
tag = serializers.PrimaryKeyRelatedField(
queryset=BookTag.objects.all(),
required=False,
allow_null=True,
)
tag_detail = AdminBookTagSerializer(source="tag", read_only=True)
volumes_detail = AdminBookVolumeSerializer(source="volumes", many=True, read_only=True) volumes_detail = AdminBookVolumeSerializer(source="volumes", many=True, read_only=True)
number_of_volumes = serializers.SerializerMethodField() number_of_volumes = serializers.SerializerMethodField()
researchers = AdminBookResearcherSerializer(many=True, required=False) researchers = AdminBookResearcherSerializer(many=True, required=False)
@ -1605,7 +1645,8 @@ class AdminBookEditionSerializer(serializers.ModelSerializer):
"source_url", "source_url",
"isbn", "isbn",
"notes", "notes",
"tags",
"tag",
"tag_detail",
"volumes_detail", "volumes_detail",
"researchers", "researchers",
"editors", "editors",

13
apps/hadis/urls.py

@ -3,19 +3,19 @@ from rest_framework.routers import SimpleRouter
from .views.category import HadisCategorySectListView, HadisCategoryTreeView, CategoriesView, CategoriesBySectView, HadisCategorySelectBySectView, HadisCategorySelectBySectSourceView , HadisCategoryTreeNormalView ,test_deploy,debug_headers,HadisCategoryXMindView from .views.category import HadisCategorySectListView, HadisCategoryTreeView, CategoriesView, CategoriesBySectView, HadisCategorySelectBySectView, HadisCategorySelectBySectSourceView , HadisCategoryTreeNormalView ,test_deploy,debug_headers,HadisCategoryXMindView
from .views.hadis import ( from .views.hadis import (
HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView,HadisMainListView, HadisFiltersView, HadisLayersView,PinnedHadisCollectionListView, HadisFiltersSyncAPIView, HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView,HadisMainListView, HadisFiltersView, HadisLayersView,PinnedHadisCollectionListView, HadisFiltersSyncAPIView,
HadisCorrectionDetailView, HadisInterpretationDetailView
HadisCorrectionDetailView, HadisInterpretationDetailView, HadisInterpretsListView
) )
from .views.transmitter import ( from .views.transmitter import (
TransmitterView ,TransmitterDetailView, TransmitterSyncView,TransmitterOpinionView, TransmitterOriginalTextView, TransmitterFiltersView, TransmitterView ,TransmitterDetailView, TransmitterSyncView,TransmitterOpinionView, TransmitterOriginalTextView, TransmitterFiltersView,
NarratorArgumentsListView , NarratorTeachersView, NarratorStudentsView, TransmitterOriginalTextDetailView NarratorArgumentsListView , NarratorTeachersView, NarratorStudentsView, TransmitterOriginalTextDetailView
) )
from .views.reference import BookDetailView, BookReferencesView, BookReferenceSyncView, BookAttributeView
from .views.reference import BookDetailView, BookReferencesView, BookReferenceSyncView, BookAttributeView, ReferenceExcerptsListView
from .views.reference_v2 import BookReferenceV2DetailView, BookReferenceV2SyncView, BookReferenceV2ListView from .views.reference_v2 import BookReferenceV2DetailView, BookReferenceV2SyncView, BookReferenceV2ListView
from .views.version import ContentReleaseSyncView from .views.version import ContentReleaseSyncView
from .views.info import HadisInfoView from .views.info import HadisInfoView
from .views_admin import ( from .views_admin import (
AdminHadisCategoryViewSet, AdminHadisViewSet, AdminHadisCorrectionViewSet, AdminHadisInterpretationViewSet, AdminHadisStatusViewSet, AdminHadisTagViewSet, AdminHadisCollectionViewSet, AdminHadisCategoryViewSet, AdminHadisViewSet, AdminHadisCorrectionViewSet, AdminHadisInterpretationViewSet, AdminHadisStatusViewSet, AdminHadisTagViewSet, AdminHadisCollectionViewSet,
AdminBookSubjectAreaViewSet, AdminBookTypeViewSet, AdminBookAuthorViewSet, AdminBookAttributeViewSet, AdminBookReferenceImageViewSet, AdminBookReferenceDocumentViewSet, AdminBookReferenceViewSet,
AdminBookSubjectAreaViewSet, AdminBookTypeViewSet, AdminBookTagViewSet, AdminBookAuthorViewSet, AdminBookAttributeViewSet, AdminBookReferenceImageViewSet, AdminBookReferenceDocumentViewSet, AdminBookReferenceViewSet,
AdminTransmitterViewSet, AdminTransmitterReliabilityViewSet, DovodiBookSubjectAreaViewSet, DovodiBookTypeViewSet, AdminTransmitterViewSet, AdminTransmitterReliabilityViewSet, DovodiBookSubjectAreaViewSet, DovodiBookTypeViewSet,
DovodiNarratorLayerViewSet, DovodiTransmitterReliabilityViewSet, DovodiOpinionStatusViewSet, DovodiNarratorLayerViewSet, DovodiTransmitterReliabilityViewSet, DovodiOpinionStatusViewSet,
DovodiHadisSectViewSet, DovodiHadisCategoryViewSet, AdminCategoryQuranVerseViewSet, AdminHadisTransmitterViewSet, DovodiHadisSectViewSet, DovodiHadisCategoryViewSet, AdminCategoryQuranVerseViewSet, AdminHadisTransmitterViewSet,
@ -43,6 +43,7 @@ admin_router.register(r'collections', AdminHadisCollectionViewSet, basename='adm
admin_router.register(r'references', AdminBookReferenceViewSet, basename='admin-book-references') admin_router.register(r'references', AdminBookReferenceViewSet, basename='admin-book-references')
admin_router.register(r'subject-areas', AdminBookSubjectAreaViewSet, basename='admin-book-subject-areas') admin_router.register(r'subject-areas', AdminBookSubjectAreaViewSet, basename='admin-book-subject-areas')
admin_router.register(r'book-types', AdminBookTypeViewSet, basename='admin-book-types') admin_router.register(r'book-types', AdminBookTypeViewSet, basename='admin-book-types')
admin_router.register(r'book-tags', AdminBookTagViewSet, basename='admin-book-tags')
admin_router.register(r'dovodi-subject-areas', DovodiBookSubjectAreaViewSet, basename='dovodi-book-subject-areas') admin_router.register(r'dovodi-subject-areas', DovodiBookSubjectAreaViewSet, basename='dovodi-book-subject-areas')
admin_router.register(r'dovodi-book-types', DovodiBookTypeViewSet, basename='dovodi-book-types') admin_router.register(r'dovodi-book-types', DovodiBookTypeViewSet, basename='dovodi-book-types')
admin_router.register(r'book-authors', AdminBookAuthorViewSet, basename='admin-book-authors') admin_router.register(r'book-authors', AdminBookAuthorViewSet, basename='admin-book-authors')
@ -112,9 +113,12 @@ urlpatterns = [
path('narrators/', TransmitterView.as_view(), name='narrators'), path('narrators/', TransmitterView.as_view(), name='narrators'),
# Reference paths # Reference paths
path('v2/references/<str:reference_slug>/excerpts/', ReferenceExcerptsListView.as_view(), name='reference-excerpts-v2'),
path('v2/references/<str:slug>/', BookReferenceV2DetailView.as_view(), name='reference-detail-v2'), path('v2/references/<str:slug>/', BookReferenceV2DetailView.as_view(), name='reference-detail-v2'),
path('v2/references/', BookReferenceV2ListView.as_view(), name='reference-list-v2'), path('v2/references/', BookReferenceV2ListView.as_view(), name='reference-list-v2'),
path('references/<str:reference_slug>', BookDetailView.as_view(), name='reference-detail'),
path('references/<str:reference_slug>/excerpts/', ReferenceExcerptsListView.as_view(), name='reference-excerpts'),
path('references/<str:reference_slug>/', BookDetailView.as_view(), name='reference-detail'),
path('references/<str:reference_slug>', BookDetailView.as_view(), name='reference-detail-no-slash'),
path('references/', BookReferencesView.as_view(), name='references'), path('references/', BookReferencesView.as_view(), name='references'),
# Hadis detail paths (with slug, more specific) # Hadis detail paths (with slug, more specific)
@ -122,6 +126,7 @@ urlpatterns = [
path('<str:hadis_slug>/transmitters/', HadisTransmittersView.as_view(), name='hadis-transmitters'), path('<str:hadis_slug>/transmitters/', HadisTransmittersView.as_view(), name='hadis-transmitters'),
path('<str:hadis_slug>/transmitters/layers/', HadisLayersView.as_view(), name='hadis-layers'), path('<str:hadis_slug>/transmitters/layers/', HadisLayersView.as_view(), name='hadis-layers'),
path('<str:hadis_slug>/corrections/', HadisCorrectionsView.as_view(), name='hadis-corrections'), path('<str:hadis_slug>/corrections/', HadisCorrectionsView.as_view(), name='hadis-corrections'),
path('<str:hadis_slug>/interprets/', HadisInterpretsListView.as_view(), name='hadis-interprets'),
path('<str:hadis_slug>/', HadisBasicView.as_view(), name='hadis-basic'), # ← Least specific LAST path('<str:hadis_slug>/', HadisBasicView.as_view(), name='hadis-basic'), # ← Least specific LAST
# path('test/test-deploy',test_deploy , name='test'), # path('test/test-deploy',test_deploy , name='test'),

1914
apps/hadis/views/hadis.py
File diff suppressed because it is too large
View File

56
apps/hadis/views/reference.py

@ -1,10 +1,12 @@
from rest_framework.authentication import TokenAuthentication from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import ListAPIView, RetrieveAPIView,ListCreateAPIView
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.generics import ListAPIView, RetrieveAPIView, ListCreateAPIView
from rest_framework.response import Response from rest_framework.response import Response
from django.db.models import Q from django.db.models import Q
from ..models import BookReference , BookAuthor , BookReferenceImage, BookAttribute
from ..serializers.reference import BookAuthorSerializer, BookDetailSerializer , BookReferenceSerializer, BookReferenceSyncSerializer, BookAttributeSerializer
from drf_yasg.utils import swagger_auto_schema
from ..models import BookReference, BookAuthor, BookReferenceImage, BookAttribute, Hadis
from ..serializers.reference import BookAuthorSerializer, BookDetailSerializer, BookReferenceSerializer, BookReferenceSyncSerializer, BookAttributeSerializer
from ..serializers.hadis import HadisListSerializer
from ..serializers.category import get_localized_text from ..serializers.category import get_localized_text
from ..docs import book_attributes_create_swagger, book_attributes_list_swagger, book_references_list_swagger, book_authors_list_swagger, book_detail_swagger, reference_sync_swagger from ..docs import book_attributes_create_swagger, book_attributes_list_swagger, book_references_list_swagger, book_authors_list_swagger, book_detail_swagger, reference_sync_swagger
from utils.pagination import NoPagination from utils.pagination import NoPagination
@ -218,3 +220,49 @@ class BookAttributeView(ListCreateAPIView):
return self.create(request, *args, **kwargs) return self.create(request, *args, **kwargs)
class ReferenceExcerptsListView(ListAPIView):
"""
API view to retrieve all hadiths associated with a specific book reference (excerpts)
"""
serializer_class = HadisListSerializer
authentication_classes = [TokenAuthentication]
permission_classes = [AllowAny]
pagination_class = StandardResultsSetPagination
lookup_field = 'slug'
lookup_url_kwarg = 'reference_slug'
@swagger_auto_schema(
operation_summary="Get Reference Excerpts (Hadiths)",
operation_description="Returns a paginated list of all hadiths connected to this book reference.",
tags=['Dobodbi - Hadis (V2)'],
)
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def get_queryset(self):
reference_slug = self.kwargs.get('reference_slug')
return Hadis.objects.filter(
references__book_reference__slug=reference_slug,
status=True
).select_related(
'category__sect',
'hadis_status'
).distinct().order_by('id')
def get_serializer_context(self):
context = super().get_serializer_context()
user = self.request.user
if user.is_authenticated:
from apps.bookmark.models.bookmark import Bookmark
user_bookmarks = Bookmark.objects.filter(
user=user,
service=Bookmark.ServiceChoices.HADITH,
status=True
).values_list('content_id', flat=True)
context['user_bookmarked_hadis_ids'] = set(user_bookmarks)
else:
context['user_bookmarked_hadis_ids'] = set()
return context

2
apps/hadis/views/reference_v2.py

@ -156,7 +156,7 @@ class BookReferenceV2ListView(generics.ListAPIView):
return values return values
def get_queryset(self): def get_queryset(self):
qs = BookReference.objects.select_related('author').prefetch_related('tags', 'volumes__images').order_by('-created_at')
qs = BookReference.objects.select_related('author', 'tag').prefetch_related('volumes__images').order_by('-created_at')
search = self.request.query_params.get('search') search = self.request.query_params.get('search')
if search: if search:

19
apps/hadis/views_admin.py

@ -11,7 +11,7 @@ from utils.pagination import StandardResultsSetPagination, OptionalPagination
from .models import ( from .models import (
Hadis, HadisCategory, HadisCollection, HadisInCollection, HadisCorrection, HadisInterpretation, HadisStatus, HadisTag, HadisSect, HadisTransmitter, Hadis, HadisCategory, HadisCollection, HadisInCollection, HadisCorrection, HadisInterpretation, HadisStatus, HadisTag, HadisSect, HadisTransmitter,
BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, BookEdition, BookVolume,
BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, BookTag, BookEdition, BookVolume,
Transmitters, TransmitterReliability, NarratorLayer, OpinionStatus, TransmitterOpinion, TransmitterOriginalText Transmitters, TransmitterReliability, NarratorLayer, OpinionStatus, TransmitterOpinion, TransmitterOriginalText
) )
from .serializers.serializers_admin import ( from .serializers.serializers_admin import (
@ -29,6 +29,7 @@ from .serializers.serializers_admin import (
AdminHadisTagSerializer, AdminHadisTagSerializer,
AdminBookSubjectAreaSerializer, AdminBookSubjectAreaSerializer,
AdminBookTypeSerializer, AdminBookTypeSerializer,
AdminBookTagSerializer,
AdminBookAuthorSerializer, AdminBookAuthorSerializer,
AdminBookAttributeSerializer, AdminBookAttributeSerializer,
AdminBookReferenceImageSerializer, AdminBookReferenceImageSerializer,
@ -770,11 +771,27 @@ class AdminBookEditionViewSet(ModelViewSet):
return queryset.order_by("-created_at") return queryset.order_by("-created_at")
class AdminBookTagViewSet(ModelViewSet):
permission_classes = [IsAuthenticated, IsSuperAdmin]
authentication_classes = [TokenAuthentication]
serializer_class = AdminBookTagSerializer
pagination_class = None
parser_classes = (JSONParser, MultiPartParser, FormParser)
def get_queryset(self):
queryset = BookTag.objects.all()
search_query = self.request.query_params.get("search")
if search_query:
queryset = queryset.filter(title__icontains=search_query)
return queryset.order_by("-id")
class AdminBookVolumeViewSet(ModelViewSet): class AdminBookVolumeViewSet(ModelViewSet):
permission_classes = [IsAuthenticated, IsSuperAdmin] permission_classes = [IsAuthenticated, IsSuperAdmin]
authentication_classes = [TokenAuthentication] authentication_classes = [TokenAuthentication]
serializer_class = AdminBookVolumeSerializer serializer_class = AdminBookVolumeSerializer
pagination_class = None pagination_class = None
parser_classes = (MultiPartParser, FormParser, JSONParser)
def get_queryset(self): def get_queryset(self):
queryset = BookVolume.objects.all() queryset = BookVolume.objects.all()

Loading…
Cancel
Save