from django.conf import settings from django.core.validators import MinValueValidator, MaxValueValidator from rest_framework import serializers from sorl.thumbnail.parsers import parse_crop from sorl.thumbnail.parsers import ThumbnailParseError from . import models class ImageSerializer(serializers.ModelSerializer): """Serializer for model Image.""" # REQUEST file = serializers.ImageField(source='image', write_only=True) width = serializers.IntegerField(write_only=True, required=False) height = serializers.IntegerField(write_only=True, required=False) margin = serializers.CharField(write_only=True, allow_null=True, required=False, default='center') quality = serializers.IntegerField(write_only=True, allow_null=True, required=False, default=settings.THUMBNAIL_QUALITY, validators=[ MinValueValidator(1), MaxValueValidator(100)]) # RESPONSE url = serializers.ImageField(source='image', read_only=True) cropped_image = serializers.DictField(read_only=True, allow_null=True) orientation_display = serializers.CharField(source='get_orientation_display', read_only=True) class Meta: """Meta class""" model = models.Image fields = [ 'id', 'file', 'url', 'orientation', 'orientation_display', 'title', 'width', 'height', 'margin', 'quality', 'cropped_image', ] extra_kwargs = { 'orientation': {'write_only': True} } def validate(self, attrs): """Overridden validate method.""" image = attrs.get('image').image crop_width = attrs.get('width') crop_height = attrs.get('height') margin = attrs.get('margin') if crop_height and crop_width and margin: xy_image = (image.width, image.width) xy_window = (crop_width, crop_height) try: parse_crop(margin, xy_image, xy_window) except ThumbnailParseError: raise serializers.ValidationError({'margin': 'Unrecognized crop option: %s' % margin}) return attrs def create(self, validated_data): """Overridden create method.""" width = validated_data.pop('width', None) height = validated_data.pop('height', None) quality = validated_data.pop('quality') margin = validated_data.pop('margin') instance = super().create(validated_data) if instance and width and height: setattr(instance, 'cropped_image', instance.get_cropped_image( geometry=f'{width}x{height}', quality=quality, margin=margin)) return instance