gault-millau/apps/gallery/serializers.py
2019-12-11 14:58:31 +03:00

129 lines
4.2 KiB
Python

from django.conf import settings
from django.core.validators import MinValueValidator, MaxValueValidator
from django.core.files.base import ContentFile
from rest_framework import serializers
from sorl.thumbnail import get_thumbnail
from sorl.thumbnail.parsers import parse_crop, ThumbnailParseError
from django.utils.translation import gettext_lazy as _
from . import models
class ImageSerializer(serializers.ModelSerializer):
"""Serializer for model Image."""
# REQUEST
file = serializers.ImageField(source='image',
write_only=True)
# RESPONSE
url = serializers.ImageField(source='image',
read_only=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',
]
extra_kwargs = {
'orientation': {'write_only': True}
}
class CropImageSerializer(ImageSerializer):
"""Serializers for image crops."""
width = serializers.IntegerField(write_only=True, required=False)
height = serializers.IntegerField(write_only=True, required=False)
crop = serializers.CharField(write_only=True,
required=False,
default='center')
quality = serializers.IntegerField(write_only=True, required=False,
default=settings.THUMBNAIL_QUALITY,
validators=[
MinValueValidator(1),
MaxValueValidator(100)])
cropped_image = serializers.DictField(read_only=True, allow_null=True)
class Meta(ImageSerializer.Meta):
"""Meta class."""
fields = [
'id',
'url',
'orientation_display',
'width',
'height',
'crop',
'quality',
'cropped_image',
]
def validate(self, attrs):
"""Overridden validate method."""
file = self._image.image
crop_width = attrs.get('width')
crop_height = attrs.get('height')
crop = attrs.get('crop')
if (crop_height and crop_width) and (crop and crop != 'smart'):
xy_image = (file.width, file.width)
xy_window = (crop_width, crop_height)
try:
parse_crop(crop, xy_image, xy_window)
attrs['image'] = file
except ThumbnailParseError:
raise serializers.ValidationError({'margin': _('Unrecognized crop option: %s') % crop})
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')
crop = validated_data.pop('crop')
crop_params = {
'geometry': f'{width}x{height}',
'quality': quality,
'crop': crop,
}
cropped_image = self._image.get_cropped_image(**crop_params)
image = self._image
image.pk = None
crop_params['geometry_string'] = crop_params.pop('geometry')
resized = get_thumbnail(self._image.image, **crop_params)
image.image.save(resized.name, ContentFile(resized.read()), True)
image.save()
if image and width and height:
setattr(image,
'cropped_image',
cropped_image)
return image
@property
def view(self):
return self.context.get('view')
@property
def lookup_field(self):
lookup_field = 'pk'
if lookup_field in self.view.kwargs:
return self.view.kwargs.get(lookup_field)
@property
def _image(self):
"""Return image from url_kwargs."""
qs = models.Image.objects.filter(id=self.lookup_field)
if qs.exists():
return qs.first()
raise serializers.ValidationError({'detail': _('Image not found.')})