django-imagekit/imagekit/models.py

152 lines
5.1 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
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 _
2009-01-04 18:30:03 +00:00
from imagekit import specs
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
"""
2009-01-03 14:44:43 +00:00
def __init__(cls, name, bases, attrs):
2009-01-14 16:09:17 +00:00
parents = [b for b in bases if isinstance(b, ImageModelBase)]
if not parents:
return
user_opts = getattr(cls, 'IKOptions', None)
2009-01-04 18:30:03 +00:00
opts = Options(user_opts)
2009-01-03 14:44:43 +00:00
try:
2009-01-09 14:07:10 +00:00
module = __import__(opts.spec_module, {}, {}, [''])
except ImportError:
2009-01-08 22:02:24 +00:00
raise ImportError('Unable to load imagekit config module: %s' % \
2009-12-19 16:01:54 +00:00
opts.spec_module)
for spec in [spec for spec in module.__dict__.values() \
if isinstance(spec, type) \
and issubclass(spec, specs.ImageSpec) \
and spec != specs.ImageSpec]:
2009-01-04 22:14:13 +00:00
setattr(cls, spec.name(), specs.Descriptor(spec))
opts.specs.append(spec)
setattr(cls, '_ik', opts)
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
class IKOptions:
pass
2009-12-19 16:01:54 +00:00
2009-01-04 22:14:13 +00:00
def admin_thumbnail_view(self):
if not self._imgfield:
2009-03-13 17:14:53 +00:00
return None
2009-01-09 14:34:44 +00:00
prop = getattr(self, self._ik.admin_thumbnail_spec, None)
2009-01-04 22:14:13 +00:00
if prop is None:
2009-01-09 14:34:44 +00:00
return 'An "%s" image spec has not been defined.' % \
self._ik.admin_thumbnail_spec
2009-01-04 22:14:13 +00:00
else:
if hasattr(self, 'get_absolute_url'):
return u'<a href="%s"><img src="%s"></a>' % \
2009-08-31 21:00:38 +00:00
(escape(self.get_absolute_url()), escape(prop.url))
2009-01-04 22:14:13 +00:00
else:
return u'<a href="%s"><img src="%s"></a>' % \
2009-08-31 21:00:38 +00:00
(escape(self._imgfield.url), escape(prop.url))
2009-01-04 22:14:13 +00:00
admin_thumbnail_view.short_description = _('Thumbnail')
admin_thumbnail_view.allow_tags = True
2009-12-19 16:01:54 +00:00
@property
def _imgfield(self):
return getattr(self, self._ik.image_field)
2009-12-19 16:01:54 +00:00
@property
def _storage(self):
return getattr(self._ik, 'storage', self._imgfield.storage)
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):
if self._imgfield and replace:
2009-09-02 18:20:30 +00:00
self._imgfield.delete(save=False)
if hasattr(image, 'read'):
data = image.read()
else:
data = image
content = ContentFile(data)
self._imgfield.save(name, content, save)
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-07-19 17:50:31 +00:00
is_new_object = self._get_pk_val() is None
2009-01-14 16:09:17 +00:00
super(ImageModel, self).save(*args, **kwargs)
if is_new_object and self._imgfield:
2009-01-08 21:42:26 +00:00
clear_cache = False
2009-01-08 20:04:20 +00:00
spec = self._ik.preprocessor_spec
if spec is not None:
newfile = self._imgfield.storage.open(str(self._imgfield))
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(self._imgfield)
self._imgfield.storage.delete(name)
self._imgfield.storage.save(name, content)
if self._imgfield:
if clear_cache:
self._clear_cache()
self._pre_cache()
2008-12-28 21:48:21 +00:00
def delete(self):
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()
2009-01-09 14:34:44 +00:00
models.Model.delete(self)