mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-04-28 00:34:43 +00:00
Implemented post_save and post_delete handlers for ImageSpecs.
Removed the save and clear_cache methods from ImageModel (along with helpers). Now, whenever an ImageSpec is contributed to a model, handlers are created for the post_save and post_delete signals. The post_save handler does the work of running the ImageSpec processors and caching the resulting file, while the post_delete handler does the work cleaning up the cached files.
This commit is contained in:
parent
34e475885b
commit
b1c5432310
2 changed files with 49 additions and 62 deletions
|
|
@ -72,68 +72,6 @@ class ImageModel(models.Model):
|
|||
class IKOptions:
|
||||
pass
|
||||
|
||||
def _clear_cache(self):
|
||||
for spec in self._ik.specs:
|
||||
prop = getattr(self, spec.name())
|
||||
prop._delete()
|
||||
|
||||
def _pre_cache(self):
|
||||
for spec in self._ik.specs:
|
||||
if spec.pre_cache:
|
||||
prop = getattr(self, spec.name())
|
||||
prop._create()
|
||||
|
||||
def save_image(self, name, image, save=True, replace=True):
|
||||
imgfields = self._imgfields
|
||||
for imgfield in imgfields:
|
||||
if imgfield and replace:
|
||||
imgfield.delete(save=False)
|
||||
if hasattr(image, 'read'):
|
||||
data = image.read()
|
||||
else:
|
||||
data = image
|
||||
content = ContentFile(data)
|
||||
imgfield.save(name, content, save)
|
||||
|
||||
@property
|
||||
def _imgfields(self):
|
||||
return set([spec._get_imgfield(self) for spec in self._ik.specs])
|
||||
|
||||
def save(self, clear_cache=True, *args, **kwargs):
|
||||
super(ImageModel, self).save(*args, **kwargs)
|
||||
|
||||
is_new_object = self._get_pk_val() is None
|
||||
if is_new_object:
|
||||
clear_cache = False
|
||||
|
||||
imgfields = self._imgfields
|
||||
for imgfield in imgfields:
|
||||
spec = self._ik.preprocessor_spec
|
||||
if spec is not None:
|
||||
newfile = imgfield.storage.open(str(imgfield))
|
||||
img = Image.open(newfile)
|
||||
img, format = spec.process(img, self)
|
||||
if format != 'JPEG':
|
||||
imgfile = img_to_fobj(img, format)
|
||||
else:
|
||||
imgfile = img_to_fobj(img, format,
|
||||
quality=int(spec.quality),
|
||||
optimize=True)
|
||||
content = ContentFile(imgfile.read())
|
||||
newfile.close()
|
||||
name = str(imgfield)
|
||||
imgfield.storage.delete(name)
|
||||
imgfield.storage.save(name, content)
|
||||
if self._imgfields:
|
||||
if clear_cache:
|
||||
self._clear_cache()
|
||||
self._pre_cache()
|
||||
|
||||
def clear_cache(self, **kwargs):
|
||||
assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)
|
||||
self._clear_cache()
|
||||
|
||||
|
||||
post_delete.connect(ImageModel.clear_cache, sender=ImageModel)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from imagekit.lib import *
|
|||
from imagekit.utils import img_to_fobj
|
||||
from django.core.files.base import ContentFile
|
||||
from django.utils.encoding import force_unicode, smart_str
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
|
||||
|
||||
class ImageSpec(object):
|
||||
|
|
@ -63,6 +64,16 @@ class ImageSpec(object):
|
|||
|
||||
def contribute_to_class(self, cls, name):
|
||||
setattr(cls, name, _ImageSpecDescriptor(self, name))
|
||||
# Connect to the signals only once for this class's attribute.
|
||||
uid = '%s.%s_%s' % (cls.__module__, cls.__name__, name)
|
||||
post_save.connect(_create_post_save_handler(name),
|
||||
sender=cls,
|
||||
weak=False,
|
||||
dispatch_uid='%s_save' % uid)
|
||||
post_delete.connect(_create_post_delete_handler(name, uid),
|
||||
sender=cls,
|
||||
weak=False,
|
||||
dispatch_uid='%s.delete' % uid)
|
||||
|
||||
|
||||
class BoundImageSpec(ImageSpec):
|
||||
|
|
@ -227,3 +238,41 @@ class _ImageSpecDescriptor(object):
|
|||
return self._spec
|
||||
else:
|
||||
return BoundImageSpec(instance, self._spec, self._property_name)
|
||||
|
||||
|
||||
def _create_post_save_handler(accessor_name):
|
||||
def handler(sender, instance=None, created=False, raw=False, **kwargs):
|
||||
if raw:
|
||||
return
|
||||
accessor = getattr(instance, accessor_name)
|
||||
spec = accessor.spec
|
||||
imgfield = spec._get_imgfield(instance)
|
||||
newfile = imgfield.storage.open(str(imgfield))
|
||||
img = Image.open(newfile)
|
||||
img, format = spec.process(img, instance)
|
||||
if format != 'JPEG':
|
||||
imgfile = img_to_fobj(img, format)
|
||||
else:
|
||||
imgfile = img_to_fobj(img, format,
|
||||
quality=int(spec.quality),
|
||||
optimize=True)
|
||||
content = ContentFile(imgfile.read())
|
||||
newfile.close()
|
||||
name = str(imgfield)
|
||||
imgfield.storage.delete(name)
|
||||
imgfield.storage.save(name, content)
|
||||
if not created:
|
||||
accessor._delete()
|
||||
accessor._create()
|
||||
return handler
|
||||
|
||||
|
||||
def _create_post_delete_handler(accessor_name, uid):
|
||||
def handler(sender, instance=None, **kwargs):
|
||||
assert instance._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (instance._meta.object_name, instance._meta.pk.attname)
|
||||
accessor = getattr(instance, accessor_name)
|
||||
accessor._delete()
|
||||
post_save.disconnect(dispatch_uid='%s_save' % uid)
|
||||
post_delete.disconnect(dispatch_uid='%s.delete' % uid)
|
||||
|
||||
return handler
|
||||
|
|
|
|||
Loading…
Reference in a new issue