Removed image field from IKModel and fixed a ton of bugs

This commit is contained in:
Justin Driscoll 2009-01-06 14:00:53 -05:00
parent 64f4264c3d
commit fe5a3cccf3
5 changed files with 84 additions and 51 deletions

View file

@ -16,7 +16,7 @@ class IKModelBase(ModelBase):
if not parents:
return
user_opts = getattr(cls, 'IK', None)
user_opts = getattr(cls, 'IKConfig', None)
opts = Options(user_opts)
try:
@ -24,11 +24,13 @@ class IKModelBase(ModelBase):
except ImportError:
raise ImportError('Unable to load imagekit config module: %s' % opts.config_module)
for spec in [spec for spec in module.__dict__.values() if \
isinstance(spec, type) and issubclass(spec, specs.ImageSpec)]:
for spec in [spec for spec in module.__dict__.values() \
if isinstance(spec, type) \
and issubclass(spec, specs.ImageSpec) \
and spec != specs.ImageSpec]:
setattr(cls, spec.name(), specs.Descriptor(spec))
opts.specs.append(spec)
setattr(cls, '_ik', opts)
@ -41,12 +43,10 @@ class IKModel(models.Model):
"""
__metaclass__ = IKModelBase
image = models.ImageField(_('image'), upload_to='photos')
class Meta:
abstract = True
class IK:
class IKConfig:
pass
def admin_thumbnail_view(self):
@ -59,21 +59,25 @@ class IKModel(models.Model):
(self.get_absolute_url(), prop.url)
else:
return u'<a href="%s"><img src="%s"></a>' % \
(self.image.url, prop.url)
(self.ik_image_field.url, prop.url)
admin_thumbnail_view.short_description = _('Thumbnail')
admin_thumbnail_view.allow_tags = True
@property
def ik_image_field(self):
return getattr(self, self._ik.image_field)
@property
def cache_dir(self):
""" Returns the path to the image cache directory """
return os.path.join(os.path.dirname(self.image.path),
self._ik.cache_dir_name)
return os.path.join(os.path.dirname(self.ik_image_field.path),
self._ik.cache_dir)
@property
def cache_url(self):
""" Returns a url pointing to the image cache directory """
return '/'.join([os.path.dirname(self.image.url),
self._ik.cache_dir_name])
return '/'.join([os.path.dirname(self.ik_image_field.url),
self._ik.cache_dir])
def _cleanup_cache_dirs(self):
try:
@ -94,12 +98,12 @@ class IKModel(models.Model):
prop.create()
def save(self, *args, **kwargs):
if self._get_pk_val():
self._clear_cache()
#if self._get_pk_val():
# self._clear_cache()
super(IKModel, self).save(*args, **kwargs)
self._pre_cache()
#self._pre_cache()
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()
self._clear_cache()
super(IKModel, self).delete()

View file

@ -4,19 +4,14 @@ class Options(object):
""" Class handling per-model imagekit options
"""
# Images will be resized to fit if they are larger than max_image_size
image_field = 'image'
max_image_size = None
# Media subdirectories
image_dir_name = 'images'
cache_dir_name = 'cache'
# If given the image view count will be saved as this field name
cache_dir = 'ik_cache'
save_count_as = None
# String pattern used to generate cache file names
cache_filename_format = "%(filename)s_%(specname)s.%(extension)s"
# Configuration options coded in the models itself
config_module = 'imagekit.config'
specs = []
def __init__(self, opts):
for key, value in opts.__dict__.iteritems():
setattr(self, key, value)
setattr(self, key, value)
self.specs = []

View file

@ -42,11 +42,11 @@ class Resize(ImageProcessor):
box = (box_left, box_upper, box_right, box_lower)
image = image.resize((int(resize_x), int(resize_y)), Image.ANTIALIAS).crop(box)
else:
if not cls.width == 0 and not cls.height == 0:
if not cls.width is None and not cls.height is None:
ratio = min(float(cls.width)/cur_width,
float(cls.height)/cur_height)
else:
if cls.width == 0:
if cls.width is None:
ratio = float(cls.height)/cur_height
else:
ratio = float(cls.width)/cur_width

View file

@ -52,16 +52,20 @@ class Accessor(object):
def create(self):
if not os.path.isdir(self._obj.cache_dir):
os.makedirs(self._obj.cache_dir)
self._img = self.spec.process(Image.open(self._obj.image.path), save_as=self.path)
self._img = self.spec.process(Image.open(self._obj.ik_image_field.path), save_as=self.path)
def delete(self):
if self.exists:
os.remove(self.path)
self._img = None
@property
def exists(self):
return os.path.isfile(self.path)
@property
def name(self):
filename, ext = os.path.splitext(os.path.basename(self._obj.image.path))
filename, ext = os.path.splitext(os.path.basename(self._obj.ik_image_field.path))
return self._obj._ik.cache_filename_format % \
{'filename': filename,
'specname': self.spec.name(),
@ -75,17 +79,13 @@ class Accessor(object):
def url(self):
if not self.exists:
self.create()
if self.spec.increment_count():
if self.spec.increment_count:
fieldname = self._obj._ik.save_count_as
if fieldname is not None:
current_count = getattr(self._obj, fieldname)
setattr(self._obj, fieldname, current_count + 1)
return '/'.join([self._obj.cache_url, self.name])
@property
def exists(self):
return os.path.isfile(self.path)
@property
def image(self):
if self._img is None:
@ -113,9 +113,6 @@ class Accessor(object):
class Descriptor(object):
def __init__(self, spec):
self._spec = spec
self._prop = None
def __get__(self, obj, type=None):
if self._prop is None:
self._prop = Accessor(obj, self._spec)
return self._prop
return Accessor(obj, self._spec)

View file

@ -1,5 +1,5 @@
import os
import StringIO
import tempfile
import unittest
from django.conf import settings
from django.core.files.base import ContentFile
@ -8,34 +8,71 @@ from django.test import TestCase
from models import IKModel
from specs import ImageSpec
from imagekit import processors
from imagekit import Image
class ResizeToWidth(processors.Resize):
width = 100
class ResizeToHeigh(processors.Resize):
height = 100
class ResizeToFit(processors.Resize):
width = 100
height = 100
class ResizeCrop(ResizeToFit):
crop = True
class TestResizeToWidth(ImageSpec):
access_as = 'to_width'
processors = [ResizeToWidth]
IMG_PATH = os.path.join(os.path.dirname(__file__), 'test.jpg')
class TestPhoto(IKModel):
""" Minimal ImageModel class for testing """
name = models.CharField(max_length=30)
image = models.ImageField(upload_to='images')
class IKConfig:
config_module = 'imagekit.tests'
class PLTest(TestCase):
class IKTest(TestCase):
""" Base TestCase class """
def setUp(self):
Image.new('RGB', (100, 100)).save(IMG_PATH, 'JPEG')
self.p = TestPhoto(name='landscape')
self.p.image.save(os.path.basename(IMG_PATH),
ContentFile(open(IMG_PATH, 'rb').read()))
# create a test image using tempfile and PIL
self.tmp = tempfile.TemporaryFile()
Image.new('RGB', (800, 600)).save(self.tmp, 'JPEG')
self.tmp.seek(0)
self.p = TestPhoto()
self.p.image.save(os.path.basename('test.jpg'),
ContentFile(self.tmp.read()))
self.p.save()
# destroy temp file
self.tmp.close()
def test_config(self):
self.assertEqual(self.p._ik.specs, [TestResizeToWidth])
def test_setup(self):
self.assert_(self.p.image is not None)
self.assertEqual(self.p.image.width, 100 )
self.assertEqual(self.p.image.width, 800)
self.assertEqual(self.p.image.height, 600)
def test_accessor(self):
self.assertEqual(self.p.admin_thumbnail.width, 100)
def test_to_width(self):
self.assertEqual(self.p.to_width.width, 100)
self.assertEqual(self.p.to_width.height, 75)
def test_url(self):
url = "%s/%s" % (self.p.cache_url, 'test_to_width.jpg')
self.assertEqual(self.p.to_width.url, url)
def tearDown(self):
os.remove(IMG_PATH)
# make sure image file is deleted
path = self.p.image.path
self.p.delete()
self.failIf(os.path.isfile(path))