You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

575 lines
23 KiB

from rest_framework import serializers
from rest_framework.pagination import PageNumberPagination
from ..models import BookReference, BookAuthor, BookEdition, BookVolume, BookTag, BookResearcher, BookEditor
from .category import get_localized_text
from apps.hadis.serializers import HadisListSerializer, HadisShortSerializer
from ..serializers.category import LocalizedField
from ..serializers.reference import BookAttributeSerializer, BookReferenceImageSerializer
from utils import absolute_https_url
class BookTagV2Serializer(serializers.ModelSerializer):
title = LocalizedField()
class Meta:
model = BookTag
fields = ['id', 'title']
class BookAuthorV2Serializer(serializers.ModelSerializer):
name = LocalizedField()
class Meta:
model = BookAuthor
fields = ['id', 'name', 'slug', 'image']
class BookResearcherV2Serializer(serializers.ModelSerializer):
name = LocalizedField()
author = BookAuthorV2Serializer(read_only=True)
author_id = serializers.SerializerMethodField()
slug = serializers.SerializerMethodField()
class Meta:
model = BookResearcher
fields = ['id', 'name', 'slug', 'author', 'author_id']
def get_author_id(self, obj):
return obj.author_id
def get_slug(self, obj):
if obj.author and obj.author.slug:
return obj.author.slug
return obj.slug
class BookEditorV2Serializer(serializers.ModelSerializer):
name = LocalizedField()
author = BookAuthorV2Serializer(read_only=True)
author_id = serializers.SerializerMethodField()
slug = serializers.SerializerMethodField()
class Meta:
model = BookEditor
fields = ['id', 'name', 'slug', 'author', 'author_id']
def get_author_id(self, obj):
return obj.author_id
def get_slug(self, obj):
if obj.author and obj.author.slug:
return obj.author.slug
return obj.slug
class BookReferenceV2ListSerializer(serializers.ModelSerializer):
title = LocalizedField()
authors = serializers.SerializerMethodField()
tag = BookTagV2Serializer(read_only=True)
number_of_volumes = serializers.SerializerMethodField()
image = serializers.SerializerMethodField()
class Meta:
model = BookReference
fields = ['id', 'slug', 'title', 'authors', 'number_of_volumes', 'tag', 'image']
def get_authors(self, obj):
if obj.author:
return [BookAuthorV2Serializer(obj.author, context=self.context).data]
return []
def get_number_of_volumes(self, obj):
return obj.volumes.count()
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()
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()
if first_image and first_image.image:
request = self.context.get('request')
if request:
return absolute_https_url(first_image.image.url, request)
return absolute_https_url(first_image.image.url)
return None
def _get_book_editions(obj):
seen = set()
result = []
for ed in obj.editions.all():
seen.add(ed.id)
result.append(ed)
if hasattr(obj, 'editions_list'):
for ed in obj.editions_list.all():
if ed.id not in seen:
seen.add(ed.id)
result.append(ed)
return result
class BookEditionV2Serializer(serializers.ModelSerializer):
title = LocalizedField()
publisher = serializers.SerializerMethodField()
notes = LocalizedField()
tag = BookTagV2Serializer(read_only=True)
publication_place = serializers.SerializerMethodField()
researchers = BookResearcherV2Serializer(many=True, read_only=True)
editors = BookEditorV2Serializer(many=True, read_only=True)
number_of_volumes = serializers.SerializerMethodField()
class Meta:
model = BookEdition
fields = [
'id', 'title', 'publisher', 'publication_place', 'edition_number',
'year_of_publication', 'number_of_volumes', 'notes', 'source_url', 'tag',
'researchers', 'editors'
]
def get_publisher(self, obj):
request = self.context.get("request")
if getattr(obj, "publisher_item_id", None) and obj.publisher_item and obj.publisher_item.title:
val = get_localized_text(obj.publisher_item.title, request)
if val:
return val
return get_localized_text(obj.publisher, request) if obj.publisher else None
def get_number_of_volumes(self, obj):
count = obj.volumes.count()
if count > 0:
return count
return obj.number_of_volumes or 0
def get_publication_place(self, obj):
request = self.context.get("request")
city_src = (
obj.city_of_publication_city.title
if (getattr(obj, "city_of_publication_city_id", None) and obj.city_of_publication_city and obj.city_of_publication_city.title)
else obj.city_of_publication
)
country_src = (
obj.country_of_publication_country.title
if (getattr(obj, "country_of_publication_country_id", None) and obj.country_of_publication_country and obj.country_of_publication_country.title)
else obj.country_of_publication
)
city = get_localized_text(city_src, request) if city_src else ""
country = get_localized_text(country_src, request) if country_src else ""
return {
"city": city,
"country": country
}
class BookVolumeV2Serializer(serializers.ModelSerializer):
image = serializers.SerializerMethodField()
file = serializers.SerializerMethodField()
class Meta:
model = BookVolume
fields = ['id', 'title', 'image', 'file']
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()
if first_image and first_image.image:
if request:
return absolute_https_url(first_image.image.url, request)
return absolute_https_url(first_image.image.url)
return None
def get_file(self, obj):
request = self.context.get('request')
if obj.file:
if request:
return absolute_https_url(obj.file.url, request)
return absolute_https_url(obj.file.url)
first_doc = obj.documents.order_by('order').first()
if first_doc and first_doc.file:
if request:
return absolute_https_url(first_doc.file.url, request)
return absolute_https_url(first_doc.file.url)
return None
class BookReferenceV2DetailSerializer(serializers.ModelSerializer):
title = LocalizedField()
authors = serializers.SerializerMethodField()
image = serializers.SerializerMethodField()
tag = BookTagV2Serializer(read_only=True)
information = serializers.SerializerMethodField()
volumes = serializers.SerializerMethodField()
class Meta:
model = BookReference
fields = ['id', 'title', 'authors', 'image', 'tag', 'information', 'volumes']
def get_authors(self, obj):
if obj.author:
return [BookAuthorV2Serializer(obj.author, context=self.context).data]
return []
def get_image(self, obj):
first_image = obj.images.filter(book_volume__isnull=True).order_by('order').first()
if not first_image:
first_image = obj.images.order_by('order').first()
if first_image and first_image.image:
request = self.context.get('request')
if request:
return absolute_https_url(first_image.image.url, request)
return absolute_https_url(first_image.image.url)
return None
def get_information(self, obj):
request = self.context.get("request")
summary = get_localized_text(obj.description, request) if obj.description else ""
all_editions = _get_book_editions(obj)
valid_editions = [ed for ed in all_editions if ed.volumes.exists()] or all_editions
editions = BookEditionV2Serializer(valid_editions, many=True, context=self.context).data
return {
"summary": summary,
"editions": editions
}
def get_volumes(self, obj):
if obj.has_editions:
editions = _get_book_editions(obj)
editions_data = []
request = self.context.get("request")
for ed in editions:
vol_qs = ed.volumes.all()
if not vol_qs.exists():
continue
ed_title = get_localized_text(ed.title, request) if ed.title else None
editions_data.append({
"edition_id": ed.id,
"edition_title": ed_title,
"edition_statement": ed.edition_number or ed_title or f"Edition {ed.id}",
"volumes": BookVolumeV2Serializer(vol_qs, many=True, context=self.context).data
})
return {
"has_editions": True,
"editions_volumes": editions_data,
"all_volumes": []
}
else:
return {
"has_editions": False,
"editions_volumes": [],
"all_volumes": BookVolumeV2Serializer(obj.volumes.all(), many=True, context=self.context).data
}
class BookReferenceV2SyncSerializer(serializers.ModelSerializer):
title = LocalizedField()
authors = serializers.SerializerMethodField()
attributes = BookAttributeSerializer(many=True, read_only=True)
images = BookReferenceImageSerializer(many=True, read_only=True)
information = serializers.SerializerMethodField()
hadises = serializers.SerializerMethodField()
volumes = serializers.SerializerMethodField()
class Meta:
model = BookReference
fields = [
'id', 'title', 'slug', 'share_link', 'rate', 'has_editions', 'authors',
'attributes', 'images', 'information', 'hadises', 'volumes'
]
def get_authors(self, obj):
if obj.author:
return [BookAuthorV2Serializer(obj.author, context=self.context).data]
return []
def get_information(self, obj):
request = self.context.get("request")
summary = get_localized_text(obj.description, request) if obj.description else ""
all_editions = _get_book_editions(obj)
valid_editions = [ed for ed in all_editions if ed.volumes.exists()] or all_editions
editions = BookEditionV2Serializer(valid_editions, many=True, context=self.context).data
return {
"summary": summary,
"editions": editions,
"language": get_localized_text(obj.language, request) if obj.language else "",
"number_page": obj.number_page
}
def get_hadises(self, obj):
references = obj.hadis_references.all()
hadis_list = [ref.hadis for ref in references if ref.hadis]
return HadisShortSerializer(hadis_list, many=True, context=self.context).data
def get_volumes(self, obj):
if obj.has_editions:
editions = _get_book_editions(obj)
editions_data = []
request = self.context.get("request")
for ed in editions:
vol_qs = ed.volumes.all()
if not vol_qs.exists():
continue
ed_title = get_localized_text(ed.title, request) if ed.title else None
editions_data.append({
"edition_id": ed.id,
"edition_title": ed_title,
"edition_statement": ed.edition_number or ed_title or f"Edition {ed.id}",
"volumes": BookVolumeV2Serializer(vol_qs, many=True, context=self.context).data
})
return {
"has_editions": True,
"editions_volumes": editions_data,
"all_volumes": []
}
else:
return {
"has_editions": False,
"editions_volumes": [],
"all_volumes": BookVolumeV2Serializer(obj.volumes.filter(edition__isnull=True), many=True, context=self.context).data
}
from apps.hadis.models.reference import BookAuthor, BookReference
from .category import LocalizedField, ArabicLocalizedField, get_arabic_localized_text
def _get_request_lang_v2(serializer_instance) -> str:
from django.utils.translation import get_language
request = serializer_instance.context.get("request") if hasattr(serializer_instance, "context") and serializer_instance.context else None
lang = None
if request:
lang = getattr(request, "LANGUAGE_CODE", None) or request.headers.get("Accept-Language") or request.query_params.get("lang")
if not lang:
lang = get_language() or "ru"
return str(lang).split(",")[0].split("-")[0].strip().lower() or "ru"
def _resolve_author_city(city_obj, fallback_json, request, arabic=False):
if city_obj and getattr(city_obj, 'title', None):
val = get_arabic_localized_text(city_obj.title) if arabic else get_localized_text(city_obj.title, request)
if val:
return val
if fallback_json:
return get_arabic_localized_text(fallback_json) if arabic else get_localized_text(fallback_json, request)
return None
def _resolve_author_features(obj, request, arabic=False):
parts = []
for item in obj.features_list.all():
txt = get_arabic_localized_text(item.title) if arabic else get_localized_text(item.title, request)
if txt and str(txt).strip():
parts.append(str(txt).strip())
if parts:
sep = '، ' if arabic else ', '
return sep.join(parts)
if obj.features:
return get_arabic_localized_text(obj.features) if arabic else get_localized_text(obj.features, request)
return None
def _serialize_author_features_detail(obj, request):
return [
{
'id': item.id,
'slug': item.slug,
'title': get_localized_text(item.title, request),
'arabic_title': get_arabic_localized_text(item.title),
}
for item in obj.features_list.all()
]
class _BaseBookAuthorV2Mixin(serializers.Serializer):
name = LocalizedField()
arabic_name = ArabicLocalizedField(source='name')
known_as = LocalizedField()
arabic_known_as = ArabicLocalizedField(source='known_as')
scholarity = LocalizedField()
tabaqa = LocalizedField()
rutba = serializers.SerializerMethodField()
rutba_detail = serializers.SerializerMethodField()
features = serializers.SerializerMethodField()
arabic_features = serializers.SerializerMethodField()
features_detail = serializers.SerializerMethodField()
origin = serializers.SerializerMethodField()
arabic_origin = serializers.SerializerMethodField()
lived_in = serializers.SerializerMethodField()
arabic_lived_in = serializers.SerializerMethodField()
died_in = serializers.SerializerMethodField()
arabic_died_in = serializers.SerializerMethodField()
related_narrator_slug = serializers.CharField(source='related_narrator.slug', read_only=True, allow_null=True)
birth_year_hijri = serializers.SerializerMethodField()
death_year_hijri = serializers.SerializerMethodField()
age_at_death = serializers.SerializerMethodField()
birth_year_canonical = serializers.CharField(source='birth_year_hijri', read_only=True)
death_year_canonical = serializers.CharField(source='death_year_hijri', read_only=True)
age_at_death_canonical = serializers.CharField(source='age_at_death', read_only=True)
def get_birth_year_hijri(self, obj):
return obj.get_formatted_birth_year(lang=_get_request_lang_v2(self))
def get_death_year_hijri(self, obj):
return obj.get_formatted_death_year(lang=_get_request_lang_v2(self))
def get_age_at_death(self, obj):
return obj.get_formatted_age(lang=_get_request_lang_v2(self))
def get_rutba(self, obj):
request = self.context.get('request')
if obj.rutba_status:
return get_localized_text(obj.rutba_status.title, request)
return get_localized_text(obj.rutba, request) if obj.rutba else None
def get_rutba_detail(self, obj):
if obj.rutba_status:
request = self.context.get('request')
return {
'id': obj.rutba_status.id,
'title': get_localized_text(obj.rutba_status.title, request),
'slug': obj.rutba_status.slug,
'color': obj.rutba_status.color,
'main_color_code': obj.rutba_status.main_color_code,
'description': get_localized_text(obj.rutba_status.description, request),
}
return None
def get_features(self, obj):
return _resolve_author_features(obj, self.context.get('request'), arabic=False)
def get_arabic_features(self, obj):
return _resolve_author_features(obj, self.context.get('request'), arabic=True)
def get_features_detail(self, obj):
return _serialize_author_features_detail(obj, self.context.get('request'))
def get_origin(self, obj):
return _resolve_author_city(obj.origin_city, obj.origin, self.context.get('request'), arabic=False)
def get_arabic_origin(self, obj):
return _resolve_author_city(obj.origin_city, obj.origin, self.context.get('request'), arabic=True)
def get_lived_in(self, obj):
return _resolve_author_city(obj.lived_in_city, obj.lived_in, self.context.get('request'), arabic=False)
def get_arabic_lived_in(self, obj):
return _resolve_author_city(obj.lived_in_city, obj.lived_in, self.context.get('request'), arabic=True)
def get_died_in(self, obj):
return _resolve_author_city(obj.died_in_city, obj.died_in, self.context.get('request'), arabic=False)
def get_arabic_died_in(self, obj):
return _resolve_author_city(obj.died_in_city, obj.died_in, self.context.get('request'), arabic=True)
class BookAuthorListSerializer(_BaseBookAuthorV2Mixin, serializers.ModelSerializer):
"""سریالایزر برای لیست نویسنده‌ها"""
class Meta:
model = BookAuthor
fields = [
'id', 'slug', 'name', 'arabic_name', 'image',
'known_as', 'arabic_known_as', 'scholarity', 'tabaqa',
'rutba', 'rutba_detail',
'features', 'arabic_features', 'features_detail',
'origin', 'arabic_origin', 'lived_in', 'arabic_lived_in', 'died_in', 'arabic_died_in',
'birth_year_hijri', 'death_year_hijri', 'age_at_death',
'birth_year_canonical', 'death_year_canonical', 'age_at_death_canonical',
'birth_year_miladi', 'death_year_miladi',
'related_narrator_slug',
]
class BookAuthorDetailSerializer(_BaseBookAuthorV2Mixin, serializers.ModelSerializer):
"""سریالایزر برای دیتیل یک نویسنده"""
class Meta:
model = BookAuthor
fields = [
'id', 'slug', 'name', 'arabic_name', 'image',
'known_as', 'arabic_known_as', 'scholarity', 'tabaqa',
'rutba', 'rutba_detail',
'features', 'arabic_features', 'features_detail',
'origin', 'arabic_origin', 'lived_in', 'arabic_lived_in', 'died_in', 'arabic_died_in',
'birth_year_hijri', 'death_year_hijri', 'age_at_death',
'birth_year_canonical', 'death_year_canonical', 'age_at_death_canonical',
'birth_year_miladi', 'death_year_miladi',
'related_narrator_slug',
]
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(obj.author.name)] if obj.author else []
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 absolute_https_url(first_image.image.url, request)
return absolute_https_url(first_image.image.url)
return None
# یک سریالایزر مینیمال برای کتاب‌ها داخل سینک
class BookAuthorSyncReferenceSerializer(serializers.ModelSerializer):
title = LocalizedField()
class Meta:
model = BookReference
fields = ['id', 'slug', 'title']
class BookAuthorSyncSerializer(_BaseBookAuthorV2Mixin, serializers.ModelSerializer):
"""
سریالایزر برای سینک آفلاین تمام نویسنده‌ها.
شامل تمام اطلاعات و لیست کتاب‌های متصل به این نویسنده.
"""
# اضافه کردن لیست کتاب‌ها
books = BookAuthorSyncReferenceSerializer(source='book_references', many=True, read_only=True)
class Meta:
model = BookAuthor
fields = [
'id',
'slug',
'name',
'arabic_name',
'known_as',
'arabic_known_as',
'scholarity',
'tabaqa',
'rutba',
'rutba_detail',
'features',
'arabic_features',
'features_detail',
'origin',
'arabic_origin',
'lived_in',
'arabic_lived_in',
'died_in',
'arabic_died_in',
'birth_year_hijri',
'death_year_hijri',
'age_at_death',
'birth_year_canonical',
'death_year_canonical',
'age_at_death_canonical',
'birth_year_miladi',
'death_year_miladi',
'books', # 👈 لیست کتاب‌های هر نویسنده
'related_narrator_slug'
]