Monday, December 10, 2007

Normalize name and size images in Django (and adding thumbnails)

I wanted to assign an image to every element in a model. I wanted them to have a thumbnail, and to have normalized sizes and names. And of course, I want my application to do everything automatically.

The best method I've found is next, modifying models.py (note that PIL must be installed):

def rename_image(src, field, id):
    file_ext = os.path.splitext(src)[1].lower().replace('jpg', 'jpeg')
    dst = 'img/uploaded/work_%s/%s_%s%s' % (field, field, id, file_ext)
    return dst



def resize_image(src, dst, size):
    from PIL import Image
    image = Image.open(src)
    image.thumbnail(size, Image.ANTIALIAS)
    image.save('%s%s' % (settings.MEDIA_ROOT, dst))
    return dst



class MyModel(models.Model):
    image = models.ImageField(upload_to='img/uploaded/work_image', verbose_name=_('imagen'))
    thumbnail = models.ImageField(editable=False, upload_to='img/uploaded/work_thumbnail')
    [...]



    def save(self):
        super(MyModel, self).save()
        if self.image != rename_image(self.image, 'image', self.id):
            original_filename = self.get_image_filename()
            self.thumbnail = resize_image(original_filename, rename_image(original_filename, 'thumbnail', self.id), [100, 75])
            self.image = resize_image(original_filename, rename_image(original_filename, 'image', self.id), [640, 480])
            if os.path.exists(original_filename):
                os.remove(original_filename)
            super(MyModel, self).save()

2 comments:

  1. great post, helpful. thx.

    ReplyDelete
  2. I see, this isn't a very clean approach, suppose the "if-part" of save() method takes some long time, during this time unscaled image and old thumbnail (or no at all) would be served to users.

    Is this first super.save() really necessary? Can we call save() one time after "if"?

    ReplyDelete