# encoding=utf-8 import os from PIL import Image from uuid import uuid4 from django.db import models from lms import settings from lms.settings import DOMAIN from lms.tools import random_string import django.utils.timezone from django.core.files.base import File from django.utils.deconstruct import deconstructible @deconstructible class PathAndRename(object): def __init__(self, sub_path): self.path = sub_path def __call__(self, instance, filename): ext = filename.split('.')[-1] # set filename as random string filename = '{}.{}'.format(uuid4().hex, ext) # return the whole path to the file return os.path.join(self.path, filename) path_and_rename = PathAndRename("personal_files") class FormatIndex(models.Model): FILETYPES = ( ('F', 'FILE'), ('I', 'IMAGE') ) f_type = models.CharField(verbose_name=u'Тип файла', choices=FILETYPES, max_length=1, default='F') name = models.CharField(verbose_name=u'Формат', max_length=255) description = models.CharField(verbose_name=u'Имя', max_length=255, default='') icon = models.ImageField(verbose_name=u'Иконка', upload_to='formatindex', blank=True) icon_class = models.CharField(verbose_name=u'Иконка', max_length=255, blank=True) def __unicode__(self): return u'%s' % self.name def __str__(self): return '%s' % self.name class Meta: verbose_name = u'Формат' verbose_name_plural = u'Индекс форматов' class Storage(models.Model): loaded = models.BooleanField(verbose_name=u'Загруженно', default=False) name = models.CharField(verbose_name=u'Имя файла', max_length=255, blank=True, default='') key = models.CharField(verbose_name=u'Ключь файла', max_length=255, null=True, unique=True, blank=True) original = models.FileField(verbose_name=u'Файл', upload_to=path_and_rename) f_format = models.ForeignKey(FormatIndex, verbose_name=u'Формат файла', blank=True, null=True) description = models.TextField(verbose_name=u'Дополнение к файлам', default='', blank=True) date = models.DateTimeField(verbose_name=u'Дата загрузки', default=django.utils.timezone.now) error = models.BooleanField(verbose_name=u'Ошибка', default=False) def __unicode__(self): return u'%s' % self.name def __str__(self): return '%s' % self.name def save(self, *args, **kwargs): if self.original: if not self.f_format: try: self.f_format = FormatIndex.objects.get(name=str(self.original.name.split('.')[1]).upper()) except FormatIndex.DoesNotExist: self.f_format = FormatIndex.objects.get(name='*') if not self.name: self.name = str(self.original.name.split('.')[0].encode('utf-8')) if not self.key: self.key = random_string().upper() super(Storage, self).save(*args, **kwargs) def get_name_for_user(self): return self.name if self.name else self.f_format.description def get_file_name(self): return self.original.name.split('/')[1] def get_url(self, type_in): if self.f_format.f_type == 'F': return self.original.url elif self.f_format.f_type == 'I': try: file_ = CroppedImage.objects.get(original=self) except CroppedImage.DoesNotExist: file_ = CroppedImage.objects.create(original=self) if type_in: if type_in == 'big' or type_in == 'middle' or type_in == 'small': if not file_.big or not file_.middle or not file_.small: fix_crop(file_) return file_.get_cart(type_in) else: return '{0}{1}'.format(DOMAIN, self.original.url) return '{0}{1}'.format(DOMAIN, self.original.url) class Meta: verbose_name = u'Файл' verbose_name_plural = u'Файлы' class CroppedImage(models.Model): original = models.ForeignKey('Storage', verbose_name=u'Оригинал') big = models.ImageField(verbose_name=u'Большое изображение', upload_to='personal_files', blank=True, null=True) middle = models.ImageField(verbose_name=u'Среднее изображение', upload_to='personal_files', blank=True, null=True) small = models.ImageField(verbose_name=u'Маленькое изображение', upload_to='personal_files', blank=True, null=True) cropped = models.BooleanField(verbose_name=u'Обрезан', default=False) def __unicode__(self): return u'%s' % self.original.key def __str__(self): return '%s' % self.original.key def get_cart(self, type_in): if type_in == 'big': return self.big.url elif type_in == 'middle': return self.middle.url elif type_in == 'small': return self.small.url class Meta: verbose_name = u'Картинка' verbose_name_plural = u'Картинки' IMAGE_TMP = settings.MEDIA_ROOT + 'tmp/' def save_resize_image(filename, pil_img, save_field, file_format): temp_image = open(os.path.join(IMAGE_TMP, filename), 'wb') if file_format.upper() == 'GIF': save_gif(pil_img, temp_image) else: pil_img.save(temp_image, file_format) thumb_data = open(os.path.join(IMAGE_TMP, filename), 'rb') thumb_file = File(thumb_data) save_field.save(filename + '.' + file_format, thumb_file) def save_gif(pil_img, path): if 'transparency' in pil_img.info: transparency = pil_img.info['transparency'] pil_img.save(path, 'GIF', transparency=transparency) else: pil_img.save(path, 'GIF') def fix_crop(crop): if not crop.cropped or not crop.big or not crop.middle or not crop.small: clip_ip = crop.original.key small = (50, 50) middle = (100, 100) big = (256, 256) file_format = str(crop.original.original.name.split('.')[1]) file_format = 'jpeg' if file_format == 'jpg' else file_format im = Image.open(crop.original.original.path) if not crop.big: big_img = im.copy() big_img.thumbnail(big, Image.ANTIALIAS) save_resize_image(clip_ip+'_big', big_img, crop.big, file_format) if not crop.middle: middle_img = im.copy() middle_img.thumbnail(middle, Image.ANTIALIAS) save_resize_image(clip_ip+'_middle', middle_img, crop.middle, file_format) if not crop.small: small_img = im.copy() small_img.thumbnail(small, Image.ANTIALIAS) save_resize_image(clip_ip+'_small', small_img, crop.small, file_format) if crop.big and crop.middle and crop.small: crop.cropped = True crop.save()