mirror of
https://github.com/pinry/pinry.git
synced 2025-11-13 16:45:41 +01:00
Feature: Built django-images into Pinry
This commit is contained in:
132
django_images/models.py
Normal file
132
django_images/models.py
Normal file
@@ -0,0 +1,132 @@
|
||||
import hashlib
|
||||
import os.path
|
||||
from io import BytesIO
|
||||
|
||||
from django.db import models
|
||||
from django.core.files.uploadedfile import InMemoryUploadedFile
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.dispatch import receiver
|
||||
import PIL
|
||||
|
||||
try:
|
||||
from importlib import import_module
|
||||
except ImportError:
|
||||
from django.utils.importlib import import_module
|
||||
|
||||
from . import utils
|
||||
from .settings import IMAGE_SIZES, IMAGE_PATH, IMAGE_AUTO_DELETE
|
||||
|
||||
|
||||
def hashed_upload_to(instance, filename, **kwargs):
|
||||
image_type = 'original' if isinstance(instance, Image) else 'thumbnail'
|
||||
prefix = 'image/%s/by-md5/' % (image_type,)
|
||||
hasher = hashlib.md5()
|
||||
for chunk in instance.image.chunks():
|
||||
hasher.update(chunk)
|
||||
hash_ = hasher.hexdigest()
|
||||
base, ext = os.path.splitext(filename)
|
||||
return '%(prefix)s%(first)s/%(second)s/%(hash)s/%(base)s%(ext)s' % {
|
||||
'prefix': prefix,
|
||||
'first': hash_[0],
|
||||
'second': hash_[1],
|
||||
'hash': hash_,
|
||||
'base': base,
|
||||
'ext': ext,
|
||||
}
|
||||
|
||||
|
||||
if IMAGE_PATH is None:
|
||||
upload_to = hashed_upload_to
|
||||
else:
|
||||
if callable(IMAGE_PATH):
|
||||
upload_to = IMAGE_PATH
|
||||
else:
|
||||
parts = IMAGE_PATH.split('.')
|
||||
module_name = '.'.join(parts[:-1])
|
||||
module = import_module(module_name)
|
||||
upload_to = getattr(module, parts[-1])
|
||||
|
||||
|
||||
class Image(models.Model):
|
||||
image = models.ImageField(upload_to=upload_to,
|
||||
height_field='height', width_field='width',
|
||||
max_length=255)
|
||||
height = models.PositiveIntegerField(default=0, editable=False)
|
||||
width = models.PositiveIntegerField(default=0, editable=False)
|
||||
|
||||
def get_by_size(self, size):
|
||||
return self.thumbnail_set.get(size=size)
|
||||
|
||||
def get_absolute_url(self, size=None):
|
||||
if not size:
|
||||
return self.image.url
|
||||
try:
|
||||
return self.get_by_size(size).image.url
|
||||
except Thumbnail.DoesNotExist:
|
||||
return reverse('image-thumbnail', args=(self.id, size))
|
||||
|
||||
|
||||
class ThumbnailManager(models.Manager):
|
||||
def get_or_create_at_size(self, image_id, size):
|
||||
image = Image.objects.get(id=image_id)
|
||||
if size not in IMAGE_SIZES:
|
||||
raise ValueError("Received unknown size: %s" % size)
|
||||
try:
|
||||
thumbnail = image.get_by_size(size)
|
||||
except Thumbnail.DoesNotExist:
|
||||
img = utils.scale_and_crop(image.image, **IMAGE_SIZES[size])
|
||||
# save to memory
|
||||
buf = BytesIO()
|
||||
try:
|
||||
img.save(buf, img.format, **img.info)
|
||||
except IOError:
|
||||
if img.info.get('progression'):
|
||||
orig_MAXBLOCK = PIL.ImageFile.MAXBLOCK
|
||||
temp_MAXBLOCK = 1048576
|
||||
if orig_MAXBLOCK >= temp_MAXBLOCK:
|
||||
raise
|
||||
PIL.ImageFile.MAXBLOCK = temp_MAXBLOCK
|
||||
try:
|
||||
img.save(buf, img.format, **img.info)
|
||||
finally:
|
||||
PIL.ImageFile.MAXBLOCK = orig_MAXBLOCK
|
||||
else:
|
||||
raise
|
||||
# and save to storage
|
||||
original_dir, original_file = os.path.split(image.image.name)
|
||||
thumb_file = InMemoryUploadedFile(buf, "image", original_file,
|
||||
None, buf.tell(), None)
|
||||
thumbnail, created = image.thumbnail_set.get_or_create(
|
||||
size=size, defaults={'image': thumb_file})
|
||||
return thumbnail
|
||||
|
||||
|
||||
class Thumbnail(models.Model):
|
||||
original = models.ForeignKey(Image)
|
||||
image = models.ImageField(upload_to=upload_to,
|
||||
height_field='height', width_field='width',
|
||||
max_length=255)
|
||||
size = models.CharField(max_length=100)
|
||||
height = models.PositiveIntegerField(default=0, editable=False)
|
||||
width = models.PositiveIntegerField(default=0, editable=False)
|
||||
|
||||
objects = ThumbnailManager()
|
||||
|
||||
class Meta:
|
||||
unique_together = ('original', 'size')
|
||||
|
||||
def get_absolute_url(self):
|
||||
return self.image.url
|
||||
|
||||
|
||||
@receiver(models.signals.post_save)
|
||||
def original_changed(sender, instance, created, **kwargs):
|
||||
if isinstance(instance, Image):
|
||||
instance.thumbnail_set.all().delete()
|
||||
|
||||
|
||||
@receiver(models.signals.post_delete)
|
||||
def delete_image_files(sender, instance, **kwargs):
|
||||
if isinstance(instance, (Image, Thumbnail)) and IMAGE_AUTO_DELETE:
|
||||
if instance.image.storage.exists(instance.image.name):
|
||||
instance.image.delete(save=False)
|
||||
Reference in New Issue
Block a user