Template tags and filters

Sorl-thumbnail comes with one template tag thumbnail and three filters: is_portrait, margin and resolution. To use any of them in you templates you first need to load them:

{% load thumbnail %}



{% thumbnail source geometry [key1=value1, key2=value2...] as var %}
{% endthumbnail %}

Alternative syntax using empty:

{% thumbnail source geometry [key1=value1, key2=value2...] as var %}
{% empty %}
{% endthumbnail %}

The {% empty %} section is rendered if the thumbnail source is resolved to an empty value or an invalid image source, you can think of it as rendering when the thumbnail becomes undefined.


Source can be an ImageField, FileField, a file name (assuming default_storage), a url. What we need to know is name and storage, see how ImageFile figures these things out:

from django.utils.encoding import force_text

class ImageFile(BaseImageFile):
    _size = None

    def __init__(self, file_, storage=None):
        if not file_:
            raise ThumbnailError('File is empty.')
        # figure out name
        if hasattr(file_, 'name'):
            self.name = file_.name
            self.name = force_text(file_)
        # figure out storage
        if storage is not None:
            self.storage = storage
        elif hasattr(file_, 'storage'):
            self.storage = file_.storage
        elif url_pat.match(self.name):
            self.storage = UrlStorage()
            self.storage = default_storage


Geometry is specified as widthxheight, width or xheight. Width and height are in pixels. Geometry can either be a string or resolve into a valid geometry string. Examples:

{% thumbnail item.image "200x100" as im %}
    <img src="{{ im.url }}">
{% endthumbnail %}

{% thumbnail item.image "200" as im %}
    <img src="{{ im.url }}">
{% endthumbnail %}

{% thumbnail item.image "x100" as im %}
    <img src="{{ im.url }}">
{% endthumbnail %}

{% thumbnail item.image geometry as im %}
    <img src="{{ im.url }}">
{% endthumbnail %}

If width and height are given the image is rescaled to maximum values of height and width given. Aspect ratio preserved.


Options are passed on to the backend and engine, the backend generates the thumbnail filename from it and the engine can use it for processing. Option keys are not resolved in context but values are. Passing all options to the engine means that you can easily subclass an engine and create new features like rounded corners or what ever processing you like. The options described below are how they are used and interpreted in the shipped engines.


This option is only used if both width and height is given. Crop behaves much like css background-position. The image is first rescaled to minimum values of height and width given, this will be equivalent to the padding box in the above text. After it is rescaled it will apply the cropping options. There are some differences to the css background-position:

  • Only % and px are valid lengths (units)
  • noop (No Operation) is a valid option which means there is no cropping after the initial rescaling to minimum of width and height.

There are many overlapping options here for example center is equivalent to 50%. There is not a problem with that in it self but it is a bit of a problem if you will for sorl-thumbnail. Sorl-thumbnail will generate a new thumbnail for every unique source, geometry and options. This is a design choice because we want to stay flexible with the options and not interpret them anywhere else but in the engine methods. In clear words, be consistent in your cropping options if you don’t want to generate unnecessary thumbnails. In case you are wondering, sorl-thumbnail sorts the options so the order does not matter, same options but in different order will generate only one thumbnail.


Upscale is a boolean and controls if the image can be upscaled or not. For example if your source is 100x100 and you request a thumbnail of size 200x200 and upscale is False this will return a thumbnail of size 100x100. If upscale was True this would result in a thumbnail size 200x200 (upscaled). The default value is True.


Quality is a value between 0-100 and controls the thumbnail write quality. Default value is 95.


This controls whether to save jpeg thumbnails as progressive jpegs. Default value is True.


This controls whether to orientate the resulting thumbnail with respect to the source EXIF tags for orientation. Default value is True.


This controls the write format and thumbnail extension. Formats supported by the shipped engines are 'JPEG' and 'PNG'. Default value is 'JPEG'.


This controls the resulting thumbnails color space, valid values are: 'RGB' and 'GRAY'. Default value is 'RGB'.


Padding is a boolean and controls if the image should be padded to fit the specified geometry.

If your image is 200x100:

{% thumbnail image "100x100" padding=True as im %}

im will be 100x100 with white padding at the top and bottom. The color of the padding can be controlled with padding_color or the setting THUMBNAIL_PADDING_COLOR which defaults to #ffffff.

Images are not padded by default, but this can be changed by setting THUMBNAIL_PADDING to True.


This is the color to use for padding the image. It defaults to #ffffff and can be globally set with the setting THUMBNAIL_PADDING_COLOR.


Yes this option is called options. This needs to be a context variable that resolves to a dictionary. This dictionary can contain multiple options, for example:

options = {'colorspace': 'GRAY', 'quality': 75, 'crop': 'center'}

You can use this option together with the other options but beware that the order will matter. As soon as the keyword options is encountered all the options that have a key in options are overwritten. Similarly, options in the options dict will be overwritten by options set after the options keyword argument to the thumbnail tag.


This filter returns True if the image height is larger than the image width. Examples:

{% thumbnail item.image "100x100" %}
{% if item.image|is_portrait %}
    <div class="portrait">
        <img src="{{ im.url }}">
{% else %}
    <div class="landscape">
        <img src="{{ im.url }}">
{% endif %}
{% endthumbnail %}

{% if item.image|is_portrait %}
    {% thumbnail item.image "100x200" crop="center" %}
        <img src="{{ im.url }}">
    {% endthumbnail %}
{% else %}
    {% thumbnail item.image "200x100" crop="center" %}
        <img src="{{ im.url }}">
    {% endthumbnail %}
{% endif %}


Margin is a filter for calculating margins against a padding box. For example lets say you have an image item.image and you want to pad it vertically in a 1000x1000 box, you would simply write:

<div class="millxmill">
    <img src="{{ item.image.url }}" style="margin:{{ item.image|margin:"1000x1000" }}">

The above is a rather synthetic example the more common use case is when you want boxes of images of a certain size but you do not want to crop them:

{% for profile in profiles %}
    {% thumbnail profile.photo "100x100" as im %}
        <img src="{{ im.url }}" style="margin:{{ im|margin:"100x100" }}">
    {% empty %}
        <img src="ghost100x100.jpg">
    {% endthumbnail %}
{% enfor %}

The more problematic is to get the top margin, however the margin filter outputs all values.


Resolution is a filter for obtaining alternative resolution versions of the thumbnail. Your provided resolution must be one of the THUMBNAIL_ALTERNATIVE_RESOLUTIONS settings values (default: no alternative resolutions)

For example, let’s say you have an image item.image and you want to get the 2x DPI version of it. You would simply write:

<div class="millxmill">
    <img src="{{ item.image.url|resolution:"2x" }}">