django-imagekit/imagekit/models.py

140 lines
4.3 KiB
Python
Raw Normal View History

2008-12-31 18:40:51 +00:00
import os
2008-12-28 21:48:21 +00:00
from datetime import datetime
from django.conf import settings
2009-01-08 20:04:20 +00:00
from django.core.files.base import ContentFile
2008-12-28 21:48:21 +00:00
from django.db import models
2008-12-31 17:54:47 +00:00
from django.db.models.base import ModelBase
from django.db.models.signals import post_delete
2009-08-31 21:00:38 +00:00
from django.utils.html import conditional_escape as escape
2008-12-31 17:54:47 +00:00
from django.utils.translation import ugettext_lazy as _
from imagekit.specs import ImageSpec
2009-01-08 21:11:15 +00:00
from imagekit.lib import *
from imagekit.options import Options
2009-01-08 20:04:20 +00:00
from imagekit.utils import img_to_fobj
2008-12-28 21:48:21 +00:00
# Modify image file buffer size.
ImageFile.MAXBLOCK = getattr(settings, 'PIL_IMAGEFILE_MAXBLOCK', 256 * 2 ** 10)
# Choice tuples for specifying the crop origin.
2009-03-13 17:14:53 +00:00
# These are provided for convenience.
CROP_HORZ_CHOICES = (
(0, _('left')),
(1, _('center')),
(2, _('right')),
)
CROP_VERT_CHOICES = (
(0, _('top')),
(1, _('center')),
(2, _('bottom')),
)
2008-12-28 21:48:21 +00:00
2009-01-14 16:09:17 +00:00
class ImageModelBase(ModelBase):
""" ImageModel metaclass
2009-12-19 16:01:54 +00:00
This metaclass parses IKOptions and loads the specified specification
module.
2009-12-19 16:01:54 +00:00
"""
2011-09-08 12:30:54 +00:00
def __init__(self, name, bases, attrs):
2011-09-08 20:50:06 +00:00
user_opts = getattr(self, 'IKOptions', None)
specs = []
default_image_field = getattr(user_opts, 'default_image_field', None)
2011-09-08 20:50:06 +00:00
for k, v in attrs.items():
if isinstance(v, ImageSpec):
specs.append(v)
elif not default_image_field and isinstance(v, models.ImageField):
default_image_field = k
2011-09-08 20:50:06 +00:00
user_opts.specs = specs
user_opts.default_image_field = default_image_field
2011-09-08 20:50:06 +00:00
opts = Options(user_opts)
setattr(self, '_ik', opts)
2011-09-08 12:30:54 +00:00
ModelBase.__init__(self, name, bases, attrs)
2009-01-14 16:09:17 +00:00
class ImageModel(models.Model):
2008-12-28 21:48:21 +00:00
""" Abstract base class implementing all core ImageKit functionality
2009-12-19 16:01:54 +00:00
Subclasses of ImageModel are augmented with accessors for each defined
image specification and can override the inner IKOptions class to customize
2008-12-28 21:48:21 +00:00
storage locations and other options.
2009-12-19 16:01:54 +00:00
2008-12-28 21:48:21 +00:00
"""
2009-01-14 16:09:17 +00:00
__metaclass__ = ImageModelBase
2008-12-28 21:48:21 +00:00
class Meta:
abstract = True
2009-12-19 16:01:54 +00:00
2011-09-08 12:30:54 +00:00
class IKOptions:
pass
2008-12-28 21:48:21 +00:00
def _clear_cache(self):
2009-01-04 22:14:13 +00:00
for spec in self._ik.specs:
prop = getattr(self, spec.name())
prop._delete()
2008-12-28 21:48:21 +00:00
def _pre_cache(self):
2009-01-04 22:14:13 +00:00
for spec in self._ik.specs:
if spec.pre_cache:
prop = getattr(self, spec.name())
prop._create()
2009-12-19 16:01:54 +00:00
2009-09-02 18:26:30 +00:00
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])
2008-12-28 21:48:21 +00:00
2009-01-08 21:42:26 +00:00
def save(self, clear_cache=True, *args, **kwargs):
2009-01-14 16:09:17 +00:00
super(ImageModel, self).save(*args, **kwargs)
2011-07-04 11:09:31 +00:00
is_new_object = self._get_pk_val() is None
if is_new_object:
2009-01-08 21:42:26 +00:00
clear_cache = False
2011-07-04 11:09:31 +00:00
imgfields = self._imgfields
for imgfield in imgfields:
2009-01-08 20:04:20 +00:00
spec = self._ik.preprocessor_spec
if spec is not None:
newfile = imgfield.storage.open(str(imgfield))
2009-01-08 20:04:20 +00:00
img = Image.open(newfile)
2009-07-19 17:50:31 +00:00
img, format = spec.process(img, self)
2009-01-08 20:04:20 +00:00
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()
2008-12-28 21:48:21 +00:00
2011-03-21 10:33:47 +00:00
def clear_cache(self, **kwargs):
2008-12-28 21:48:21 +00:00
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()
2011-03-26 07:46:17 +00:00
2011-03-21 10:33:47 +00:00
post_delete.connect(ImageModel.clear_cache, sender=ImageModel)