Thumbnail generation for Django with Sorl-Thumbnail


Media is the common cause of slow page loading and rendering, and they occupy majority of the bandwidth. Though the costs of storage is not the matter of primary concern, the bandwidth is an important factor, especially with huge user base on mobiles. Compressing and resizing of images is best way to handle this situation.

Compression allows us to significantly reduce the size of images with minor loss in quality. Resizing (and cropping) makes sure that image of exactly required size is served to the client instead of a larger image unnecessarily consuming the bandwidth. This is a complex task but, sorl-thumbnail makes it a cake walk.

Installation and setup of sorl-thumbnail

The installation is straight forward as with most python packages. Install it with pip.

pip install sorl-thumbnail

After the installation, add sorl.thumbnail to the INSTALLED_APPS settings of Django. And, finally make changes to the database with

python migrate

Apart from this, sorl-thumbnail requires a key-value store. By default sorl-thumbnail uses the cached DB as the key value store, and it requires that Django is properly configured to use memcached. It can also use Redis as a key-value store or simply the database that has no other dependencies. This configuration is controlled with the THUMBNAIL_KVSTORE setting whose default value is sorl.thumbnail.kvstores.cached_db_kvstore.KVStore, the cached DB.

sorl-thumbnail also requires a python imaging library to process the images uploaded. Thankfully, by default sorl-thumbnail works with pillow which is already a requirement for image upload in Django. So the chances are you have already installed it. In that case you don't have to change or configure anything. To change this image library, use the THUMBNAIL_ENGINE setting.

Usage in templates

The sorl-thumbnail can be directly used in the templates with the thumbnail template tag. Make sure that you load the tags with

{% load thumbnail %}

Then use the as operator to assign the image to other object as follows.

{% thumbnail item.image "100x100" crop="center" as im %}
    <img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
{% endthumbnail %}

To be discrete, item.image is originally the image file object (could be ImageField) available in the context. The thumbnail tag above generates an image with dimensions 100pxX100px by cropping image at center and the result is assigned to variable im using the as operator. This variable im is used to render our image in HTML.

You can use the thumbnail tag to work on external images with their url.

{% thumbnail "" "40x40" crop="80% top" as im %}
    <img src="{{ im.url }}">
{% endthumbnail %}

The thumbnail tag allows you to nest it as needed.

{% thumbnail item.image "1000" as big %}
    {% thumbnail item.image "50x50" crop="center" as small %}
        <a href="{{ big.url}}" title="look ma!"><img src="{{ small.url }}"></a>
    {% endthumbnail %}
{% endthumbnail %}

That will display a small '50x50' image that links to a larger image (of width 1000px). You can also specify the format and image quality.

{% thumbnail item.image "100x100" format="JPEG" quality="70" as im %}
    <img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
{% endthumbnail %}

Of course, there are more options that you can use and all those are specified in the official documentation on template tags and filters.

Using the API

The low level get_thumbnail method of sorl-thumbnail allows us to generate a thumbnail from anywhere in the code, once we have an image object.

from sorl.thumbnail import get_thumbnail

im = get_thumbnail(my_file, '100x100', crop='center', quality=99)

This can be used in a model if necessary:

class Profile(models.Model):
    image = ImageField(upload_to='whatever')

    def thumbnail(self):
        if self.image:
            return get_thumbnail(self.image, '50x50', quality=90)
        return None

Some thing like that might help.

sorl-thumbnail has sorl.thumbnail.ImageField image field that can be used in models instead of the standard ImageField. It is not necessary, but will allow the model to utilize additional admin options in the Django's admin panel.


You might have been thinking that generating thumbnails dynamically (every time) is a bad idea. But sorl-thumbnail uses the key value store to lookup for thumbnails that have already been generated. Whenever a thumbnail is generated from an image it is stored (rather the reference is stored) in its key-value store. The key is generated based on the filename and its storage. When a new request for thumbnail with same options (height, width, quality etc.,) arrives it serves it from the key-value store. If it isn't available a new thumbnail is generated and it is stored in the key-value store.

As a result, if an image is changed the key-value store data concerning the image is to be deleted. Otherwise the thumbnail served might be that of another image. To overcome this, before replacing or on deleting an image, delete the file as:

from sorl.thumbnail import delete

delete(my_file) # Clears key-value store data for the image and deletes image

delete(my_file, delete_file=False) # Only clears key-value store data, but does not delete image

Sorl thumbnail is indeed a great tool for managing images in our sites and such apps make Django so perfect.

Note: All the code snippets here are from sorl-thumnail documentation.


Recent Posts






RSS / Atom