Browse Source

references authors enhanced with new data fields , endpoints added for authors list , detail , books and sync api

master
Mohsen Taba 1 month ago
parent
commit
0d384148bc
  1. 38
      apps/hadis/migrations/0018_bookauthor_features_bookauthor_known_as_and_more.py
  2. 11
      apps/hadis/models/reference.py
  3. 97
      apps/hadis/serializers/reference_v2.py
  4. 8
      apps/hadis/urls.py
  5. 68
      apps/hadis/views/reference_v2.py

38
apps/hadis/migrations/0018_bookauthor_features_bookauthor_known_as_and_more.py

@ -0,0 +1,38 @@
# Generated by Django 5.2.12 on 2026-06-21 18:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('hadis', '0017_booktag_alter_bookreference_subject_area_and_more'),
]
operations = [
migrations.AddField(
model_name='bookauthor',
name='features',
field=models.JSONField(blank=True, default=list, verbose_name='Features'),
),
migrations.AddField(
model_name='bookauthor',
name='known_as',
field=models.JSONField(blank=True, default=list, verbose_name='Known as'),
),
migrations.AddField(
model_name='bookauthor',
name='rutba',
field=models.JSONField(blank=True, default=list, verbose_name='Rutba'),
),
migrations.AddField(
model_name='bookauthor',
name='scholarity',
field=models.JSONField(blank=True, default=list, verbose_name='Scholarity'),
),
migrations.AddField(
model_name='bookauthor',
name='tabaqa',
field=models.JSONField(blank=True, default=list, verbose_name='Tabaqa'),
),
]

11
apps/hadis/models/reference.py

@ -354,12 +354,21 @@ class BookAuthor(models.Model):
""" """
Model for book reference authors Model for book reference authors
""" """
name = models.JSONField(default = list , verbose_name=_('Name'))
name = models.JSONField(default=list, verbose_name=_('Name'))
slug = models.SlugField(max_length=255, verbose_name=_('slug'), null=True, blank=True, unique=True) slug = models.SlugField(max_length=255, verbose_name=_('slug'), null=True, blank=True, unique=True)
# 👇 فیلدهای جدید اضافه شده
known_as = models.JSONField(default=list, blank=True, verbose_name=_('Known as'))
scholarity = models.JSONField(default=list, blank=True, verbose_name=_('Scholarity'))
tabaqa = models.JSONField(default=list, blank=True, verbose_name=_('Tabaqa'))
rutba = models.JSONField(default=list, blank=True, verbose_name=_('Rutba'))
features = models.JSONField(default=list, blank=True, verbose_name=_('Features'))
birth_year_hijri = models.IntegerField(verbose_name=_("Birth Year (Hijri)"), null=True, blank=True) birth_year_hijri = models.IntegerField(verbose_name=_("Birth Year (Hijri)"), null=True, blank=True)
death_year_hijri = models.IntegerField(verbose_name=_("Death Year (Hijri)"), null=True, blank=True) death_year_hijri = models.IntegerField(verbose_name=_("Death Year (Hijri)"), null=True, blank=True)
birth_year_miladi = models.IntegerField(verbose_name=_("Birth Year (Miladi)"), null=True, blank=True) birth_year_miladi = models.IntegerField(verbose_name=_("Birth Year (Miladi)"), null=True, blank=True)
death_year_miladi = models.IntegerField(verbose_name=_("Death Year (Miladi)"), null=True, blank=True) death_year_miladi = models.IntegerField(verbose_name=_("Death Year (Miladi)"), null=True, blank=True)
book_references = models.ManyToManyField( book_references = models.ManyToManyField(
BookReference, BookReference,
related_name='authors', related_name='authors',

97
apps/hadis/serializers/reference_v2.py

@ -183,3 +183,100 @@ class BookReferenceV2SyncSerializer(serializers.ModelSerializer):
"editions_volumes": [], "editions_volumes": [],
"all_volumes": BookVolumeV2Serializer(obj.volumes.all(), many=True).data "all_volumes": BookVolumeV2Serializer(obj.volumes.all(), many=True).data
} }
from apps.hadis.models.reference import BookAuthor, BookReference
from .category import LocalizedField
class BookAuthorListSerializer(serializers.ModelSerializer):
"""سریالایزر برای لیست نویسنده‌ها"""
name = LocalizedField()
class Meta:
model = BookAuthor
fields = ['id', 'slug', 'name', 'birth_year_hijri', 'birth_year_miladi']
class BookAuthorDetailSerializer(serializers.ModelSerializer):
"""سریالایزر برای دیتیل یک نویسنده"""
name = LocalizedField()
known_as = LocalizedField()
scholarity = LocalizedField()
tabaqa = LocalizedField()
rutba = LocalizedField()
features = LocalizedField()
class Meta:
model = BookAuthor
fields = [
'id', 'slug', 'name', 'known_as', 'scholarity',
'tabaqa', 'rutba', 'features',
'birth_year_hijri', 'death_year_hijri',
'birth_year_miladi', 'death_year_miladi'
]
class AuthorBookReferenceSerializer(serializers.ModelSerializer):
"""سریالایزر برای لیست رفرنس‌های (کتاب‌های) یک نویسنده"""
title = LocalizedField()
authors = serializers.SerializerMethodField()
thumbnail = serializers.SerializerMethodField()
class Meta:
model = BookReference
fields = ['id', 'slug', 'title', 'thumbnail', 'authors']
def get_authors(self, obj):
field = LocalizedField()
field._context = self.context
return [field.to_representation(author.name) for author in obj.authors.all()]
def get_thumbnail(self, obj):
# گرفتن اولین عکس آپلود شده برای این رفرنس
first_image = obj.images.order_by('order').first()
if first_image and first_image.image:
request = self.context.get('request')
if request:
return request.build_absolute_uri(first_image.image.url)
return first_image.image.url
return None
# یک سریالایزر مینیمال برای کتاب‌ها داخل سینک
class BookAuthorSyncReferenceSerializer(serializers.ModelSerializer):
title = LocalizedField()
class Meta:
model = BookReference
fields = ['id', 'slug', 'title']
class BookAuthorSyncSerializer(serializers.ModelSerializer):
"""
سریالایزر برای سینک آفلاین تمام نویسندهها.
شامل تمام اطلاعات و لیست کتابهای متصل به این نویسنده.
"""
name = LocalizedField()
known_as = LocalizedField()
scholarity = LocalizedField()
tabaqa = LocalizedField()
rutba = LocalizedField()
features = LocalizedField()
# اضافه کردن لیست کتاب‌ها
books = BookAuthorSyncReferenceSerializer(source='book_references', many=True, read_only=True)
class Meta:
model = BookAuthor
fields = [
'id',
'slug',
'name',
'known_as',
'scholarity',
'tabaqa',
'rutba',
'features',
'birth_year_hijri',
'death_year_hijri',
'birth_year_miladi',
'death_year_miladi',
'books' # 👈 لیست کتاب‌های هر نویسنده
]

8
apps/hadis/urls.py

@ -14,6 +14,7 @@ from .views_admin import (
DovodiNarratorLayerViewSet, DovodiTransmitterReliabilityViewSet, DovodiOpinionStatusViewSet, DovodiNarratorLayerViewSet, DovodiTransmitterReliabilityViewSet, DovodiOpinionStatusViewSet,
DovodiHadisSectViewSet, DovodiHadisCategoryViewSet DovodiHadisSectViewSet, DovodiHadisCategoryViewSet
) )
from .views.reference_v2 import BookAuthorListView, BookAuthorDetailView, AuthorReferencesListView, BookAuthorSyncView
from django.views.decorators.cache import cache_page from django.views.decorators.cache import cache_page
from django.views.decorators.vary import vary_on_headers from django.views.decorators.vary import vary_on_headers
@ -51,6 +52,13 @@ for prefix, viewset, basename in admin_router.registry:
viewset.swagger_schema = None viewset.swagger_schema = None
urlpatterns = [ urlpatterns = [
path('sync/authors/', BookAuthorSyncView.as_view(), name='sync-author-list'),
path('authors/', BookAuthorListView.as_view(), name='author-list'),
path('authors/<str:author_slug>/', BookAuthorDetailView.as_view(), name='author-detail'),
path('authors/<str:author_slug>/references/', AuthorReferencesListView.as_view(), name='author-references'),
# Admin endpoints # Admin endpoints
path('admin/', include(admin_router.urls)), path('admin/', include(admin_router.urls)),

68
apps/hadis/views/reference_v2.py

@ -199,3 +199,71 @@ class BookReferenceV2ListView(generics.ListAPIView):
"filters": filters_metadata, "filters": filters_metadata,
"results": serializer.data "results": serializer.data
}) })
from rest_framework.generics import ListAPIView, RetrieveAPIView
from rest_framework.permissions import AllowAny
from utils.pagination import StandardResultsSetPagination
from apps.hadis.models.reference import BookAuthor, BookReference
from apps.hadis.serializers.reference_v2 import (
BookAuthorListSerializer,
BookAuthorDetailSerializer,
AuthorBookReferenceSerializer,
BookAuthorSyncSerializer
)
class BookAuthorListView(ListAPIView):
"""
لیست تمام نویسندگان رفرنس
"""
queryset = BookAuthor.objects.all().order_by('-created_at')
serializer_class = BookAuthorListSerializer
pagination_class = StandardResultsSetPagination
permission_classes = [AllowAny]
class BookAuthorDetailView(RetrieveAPIView):
"""
دریافت اطلاعات دقیق یک نویسنده بر اساس slug
"""
queryset = BookAuthor.objects.all()
serializer_class = BookAuthorDetailSerializer
lookup_field = 'slug'
lookup_url_kwarg = 'author_slug'
permission_classes = [AllowAny]
class AuthorReferencesListView(ListAPIView):
"""
لیست تمام رفرنسها (کتابها)یی که این نویسنده در آنها تگ شده است
"""
serializer_class = AuthorBookReferenceSerializer
pagination_class = StandardResultsSetPagination
permission_classes = [AllowAny]
def get_queryset(self):
author_slug = self.kwargs.get('author_slug')
# پیدا کردن رفرنس‌هایی که این نویسنده جزو authors آن‌هاست
return BookReference.objects.filter(
authors__slug=author_slug
).prefetch_related('authors', 'images').distinct().order_by('-created_at')
class BookAuthorSyncView(generics.ListAPIView):
"""
API view to sync all Book Authors data for offline mode.
Returns complete author data and their associated books without pagination.
"""
# 👇 استفاده از prefetch_related برای جلوگیری از کرش کردن دیتابیس به خاطر N+1 Query
queryset = BookAuthor.objects.prefetch_related('book_references').order_by('id')
serializer_class = BookAuthorSyncSerializer
pagination_class = NoPagination
permission_classes = [AllowAny]
@swagger_auto_schema(
operation_summary="Sync Book Authors",
operation_description="Returns complete book authors data including their books for offline sync.",
tags=['Dobodbi - Hadis (V2)'],
)
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
Loading…
Cancel
Save