from rest_framework import serializers from django.core.files.uploadedfile import SimpleUploadedFile from utils.image_compression import maybe_compress_uploaded_file from .models import Author, Book, BookCollection, Category class AbsoluteImageField(serializers.ImageField): def to_internal_value(self, data): uploaded = super().to_internal_value(data) compressed_bytes = maybe_compress_uploaded_file(uploaded) if compressed_bytes is None: return uploaded return SimpleUploadedFile( name=getattr(uploaded, "name", "image"), content=compressed_bytes, content_type=getattr(uploaded, "content_type", None), ) def to_representation(self, value): if not value: return None request = self.context.get("request") url = value.url if hasattr(value, "url") else str(value) if request: return request.build_absolute_uri(url) return url class AbsoluteFileField(serializers.FileField): def to_representation(self, value): if not value: return None request = self.context.get("request") url = value.url if hasattr(value, "url") else str(value) if request: return request.build_absolute_uri(url) return url class AdminLibraryCategorySerializer(serializers.ModelSerializer): books_count = serializers.SerializerMethodField() class Meta: model = Category fields = ["id", "title", "slug", "status", "books_count", "created_at", "updated_at"] read_only_fields = ["id", "books_count", "created_at", "updated_at"] def get_books_count(self, obj): if hasattr(obj, "books_count_annotation"): return obj.books_count_annotation return obj.books_count class AdminLibraryCollectionSerializer(serializers.ModelSerializer): slug = serializers.CharField(required=False, allow_blank=True) class Meta: model = BookCollection fields = ["id", "title", "slug", "summary", "display_position", "status", "order", "pin_top"] class AdminAuthorSerializer(serializers.ModelSerializer): thumbnail = AbsoluteImageField(required=False, allow_null=True) image = AbsoluteImageField(required=False, allow_null=True) books_count = serializers.SerializerMethodField() remove_thumbnail = serializers.BooleanField(write_only=True, required=False, default=False) remove_image = serializers.BooleanField(write_only=True, required=False, default=False) class Meta: model = Author fields = [ "id", "full_name", "slug", "thumbnail", "image", "birth_date", "death_date", "date_of_birth", "date_of_death", "researcher_editor", "publisher", "publication_place", "edition_statement", "year", "number_of_volumes", "notes", "online_source", "tag", "books_count", "created_at", "updated_at", "remove_thumbnail", "remove_image" ] read_only_fields = ["id", "created_at", "updated_at", "books_count"] def get_books_count(self, obj): if hasattr(obj, 'books_count_annotation'): return obj.books_count_annotation return obj.books_count def create(self, validated_data): validated_data.pop("remove_thumbnail", False) validated_data.pop("remove_image", False) return super().create(validated_data) def update(self, instance, validated_data): remove_thumbnail = validated_data.pop("remove_thumbnail", False) remove_image = validated_data.pop("remove_image", False) if remove_thumbnail and instance.thumbnail: instance.thumbnail.delete(save=False) instance.thumbnail = None if remove_image and instance.image: instance.image.delete(save=False) instance.image = None return super().update(instance, validated_data) class AdminBookListSerializer(serializers.ModelSerializer): thumbnail = AbsoluteImageField(required=False, allow_null=True) book_file = AbsoluteFileField(required=False, allow_null=True) categories_detail = AdminLibraryCategorySerializer(source="categories", many=True, read_only=True) author = serializers.CharField(source='author.full_name', read_only=True) author_id = serializers.IntegerField(read_only=True) class Meta: model = Book fields = [ "id", "title", "slug", "slogan", "thumbnail", "author", "publisher", "file_type", "status", "pin", "view_count", "download_count", "created_at", "updated_at", "categories_detail", "author_id", "book_file", ] read_only_fields = ["id", "view_count", "download_count", "created_at", "updated_at"] from dj_language.models import Language class AdminBookDetailSerializer(serializers.ModelSerializer): thumbnail = AbsoluteImageField(required=False, allow_null=True) book_file = AbsoluteFileField(required=False, allow_null=True) author = serializers.PrimaryKeyRelatedField(queryset=Author.objects.all(), required=False, allow_null=True) author_detail = AdminAuthorSerializer(source='author', read_only=True) categories = serializers.PrimaryKeyRelatedField(queryset=Category.objects.all(), many=True, required=False) collections = serializers.PrimaryKeyRelatedField(queryset=BookCollection.objects.all(), many=True, required=False) categories_detail = AdminLibraryCategorySerializer(source="categories", many=True, read_only=True) collections_detail = AdminLibraryCollectionSerializer(source="collections", many=True, read_only=True) remove_thumbnail = serializers.BooleanField(write_only=True, required=False, default=False) remove_book_file = serializers.BooleanField(write_only=True, required=False, default=False) language = serializers.SlugRelatedField( slug_field='code', queryset=Language.objects.all(), allow_null=True, required=False ) bookmark_count = serializers.SerializerMethodField() class Meta: model = Book fields = [ "id", "title", "slug", "slogan", "summary_title", "summary", "description", "thumbnail", "publisher", "year_of_publication", "author", "author_detail", "isbn", "numnber_of_volume", "language", "main_themes", "notable_works", "pages_count", "status", "pin", "view_count", "download_count", "bookmark_count", "file_type", "book_file", "created_at", "updated_at", "categories", "collections", "categories_detail", "collections_detail", "remove_thumbnail", "remove_book_file", ] read_only_fields = ["id", "view_count", "download_count", "bookmark_count", "created_at", "updated_at"] def get_bookmark_count(self, obj): from apps.bookmark.models.bookmark import Bookmark return Bookmark.objects.filter(service=Bookmark.ServiceChoices.LIBRARY, content_id=obj.id, status=True).count() def create(self, validated_data): validated_data.pop("remove_thumbnail", False) validated_data.pop("remove_book_file", False) categories = validated_data.pop("categories", []) collections = validated_data.pop("collections", []) book = super().create(validated_data) if categories: book.categories.set(categories) if collections: book.collections.set(collections) return book def update(self, instance, validated_data): remove_thumbnail = validated_data.pop("remove_thumbnail", False) remove_book_file = validated_data.pop("remove_book_file", False) categories = validated_data.pop("categories", None) collections = validated_data.pop("collections", None) if remove_thumbnail and instance.thumbnail: instance.thumbnail.delete(save=False) instance.thumbnail = None if remove_book_file and instance.book_file: instance.book_file.delete(save=False) instance.book_file = None book = super().update(instance, validated_data) if categories is not None: book.categories.set(categories) if collections is not None: book.collections.set(collections) return book