Updated Jun 29, 2020

Django - ImageKit Tutorial

How to create thumbnails using the django-imagekit package.

Introduction

We use the ImageSpecField to generate an image thumbnail on the fly when a page where the image is used is accessed for the first time.

Quickstart

Install these packages:

pip install pillow django-imagekit

Add these lines to the project settings.py file:

INSTALLED_APPS = [
    'blog.apps.BlogConfig',
    # HERE
    'imagekit',
    'django.contrib.admin',
    'django.contrib.auth',
    # ...
]

# START
MEDIA_URL = '/media/' 
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# END

Add these fields to a model:

from django.db import models
from imagekit.models import ImageSpecField
from pilkit.processors import Thumbnail


class Post(models.Model):
    image = models.ImageField(upload_to='images')
    image_medium = ImageSpecField(source='image',
                                  processors=[Thumbnail(200, 100)],
                                  format='JPEG',
                                  options={'quality': 60})
    image_small = ImageSpecField(source='image',
                                 processors=[Thumbnail(100, 50)],
                                 format='JPEG',
                                 options={'quality': 60})
    slug = models.SlugField(max_length=255, unique=True)

Output image URLs in templates like this:

<img src="{{ post.image_medium.url }}">
<img src="{{ post.image_small.url }}">
<img src="{{ post.image.url }}">

Setup

Run these commands to setup a new project:

python3 -m venv venv && \
source venv/bin/activate && \
pip install --upgrade pip && \
pip install django pillow django-imagekit && \
django-admin startproject mysite . && \
python manage.py startapp blog && \
python manage.py createsuperuser
  • The django-imagekit package adds image processing functionality to our project. It requires the pillow imaging library to work.

Edit the project settings.py file and add these lines to it:

INSTALLED_APPS = [
    # START
    'blog.apps.BlogConfig',
    'imagekit',
    # END
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

# START
MEDIA_URL = '/media/' 
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# END
  • The MEDIA_URL setting defines the base URL for serving user uploaded files.
  • The MEDIA_ROOT setting defines the physical location where the files are stored in the system. In this case the files are stored in the project root media directory.

Post model

Edit the blog app models.py file and add these lines to it:

from django.db import models
from imagekit.models import ImageSpecField
from pilkit.processors import Thumbnail


class Post(models.Model):
    image = models.ImageField(upload_to='images')
    image_medium = ImageSpecField(source='image',
                                  processors=[Thumbnail(200, 100)],
                                  format='JPEG',
                                  options={'quality': 60})
    image_small = ImageSpecField(source='image',
                                 processors=[Thumbnail(100, 50)],
                                 format='JPEG',
                                 options={'quality': 60})
    slug = models.SlugField(max_length=255, unique=True)
  • The ImageSpecField field specifes an image spec that generates new images from a source field. In this case from the image field. You can pass it bunch of parameters that defines how the image is generated.
  • The Thumbnail processor creates a thumbnail and tries to be smart about how it crops it.

The processors are imported from PILKit utilities.

python manage.py makemigrations && \
python manage.py migrate

Edit the blog app admin.py file and add these lines to it:

from django.contrib import admin
from blog.models import Post

admin.site.register(Post)

URLs

Edit the project urls.py file and add these lines to it:

from django.contrib import admin
from django.urls import path

# START
from django.conf.urls.static import static
from django.conf import settings
from blog.views import PostDetailView
# END

urlpatterns = [
    # HERE
    path('blog/<slug:slug>/',
         PostDetailView.as_view(),
         name='post_detail'),
    path('admin/', admin.site.urls),
    # HERE
] + static(settings.MEDIA_URL,
           document_root=settings.MEDIA_ROOT)

PostDetailView

Edit the blog app views.py file and add these lines to it:

from django.views.generic import DetailView
from blog.models import Post


class PostDetailView(DetailView):
    model = Post

Template

Create a file called post_detail.html in the blog/templates/blog directory. Add these lines to it:

{% if post.image %}
    <img src="{{ post.image_medium.url }}">
    <img src="{{ post.image_small.url }}">
{% endif %}
  • The PostDetailView view uses a template named post_detail.html automatically without us having to specify it.
  • The thumbnails are generated when you first visit the detail page.

Visit /admin/ to create a new blog post:

Visit /blog/django-tutorial/ and you should see something like this:

You can access the original image with {{ post.image.url }}.

Images are served from the media folder:

media/images/05.jpg

Its thumbnails are served from the CACHE subdirectory:

media/CACHE/images/images/05/9bba...22ce9e.jpg