Serve Scaled Images With Django Rest Framework and Django ImageKit

Serve Scaled Images With Django Rest Framework and Django ImageKit

To achieve optimal speed for web apps and web sites its important to minimise file size at almost all cost.

Usually the biggest culprit is images (Apart from video of course), Images can easily add up to 90% of the total load your application if your are not careful.

You can mitigate this by allowing people to upload files with a maximum file size or automatically reduce the quality of the image. But that will create an obstacle between the user and your application.

We all know how irritating it is when a form we fill out or an image we upload fail due to some constraints.

Its better to allow you user to upload images of any shape and size and handle the resizing, optimisation and formatting automatically on the backend so that you user can enjoy a smooth and frictionless experience.

In this case we are working with a Django REST Framework API, and make use of a fantastic package called Django ImageKit to do all the heavy lifting for us.

Django ImageKit takes the originally uploaded image and create extra specified sizes of that same images and automatically creates cached versions of them.

Enough of the talking, let's get started.

Install Django ImageKit

Install the package via command line in your activated project environment with pip.

pip install django-imagekit

Add django-imagekit to you installed apps in settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sites',
    'rest_framework',
    'rest_framework.authtoken',
    'imagekit',
]

Create a Model that use Django ImageKit

To make use of django-imagekit create extra ImageSpecField's and specify size, format and quality.

from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill, ResizeToFill

class Article(models.Model):
    created_by          = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
    updated_by          = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="+")
    created_at          = models.DateTimeField(auto_now_add=True)
    updated_at          = models.DateTimeField(auto_now=True)
    title               = models.CharField(max_length=50)
    slug                = AutoSlugField(populate_from='title', unique=True, max_length=50)
    image               = models.ImageField(upload_to='topic', null=True, blank=True)
    image_large         = ImageSpecField(source='image', processors=[ResizeToFill(512, 512)], format='PNG', options={'quality': 70})
    image_medium        = ImageSpecField(source='image', processors=[ResizeToFill(256, 256)], format='PNG', options={'quality': 70})
    image_small         = ImageSpecField(source='image', processors=[ResizeToFill(128, 128)], format='PNG', options={'quality': 70})
    image_tag           = ImageSpecField(source='image', processors=[ResizeToFill(28, 28)], format='PNG', options={'quality': 70})
    description         = RichTextField(max_length=2000, null=True, blank=True)
    content             = RichTextField(max_length=10000, null=True, blank=True)

    class Meta:
        verbose_name = 'Article'
        verbose_name_plural = 'Articles'

Include the Cached and Resized Images in Your Serializer

A common issue when using this approach is that people don't see there images represented in the JSON output of the browsable API View.

To output the resized and cached images in your serializer you need to load it with a regular ImageField as following.

class ArticleSerializer(serializers.ModelSerializer):
    image_large = serializers.ImageField(read_only=True)
    image_medium = serializers.ImageField(read_only=True)
    image_small = serializers.ImageField(read_only=True)
    image_tag = serializers.ImageField(read_only=True)

    class Meta:
        model = Topic
        fields = [
            'created_at',
            'updated_at',
            'created_by',
            'title',
            'slug',
            'image',
            'image_large',
            'image_medium',
            'image_small',
            'image_tag',
            'description',
        ]

As you can see we specified each of the django-imagekit fields as regular ImageFields in the serializer. Without them your formatted images wouldn't be visible.

Your serializer should now output the images according to your specification.

{
"created_at": "2020-01-08T04:30:35.298160Z",
"updated_at": "2020-01-08T04:30:35.298188Z",
"created_by": 1,
"title": "An Awesome Article",
"slug": "an-awesome-article",
"image": "https://images.somedomain.com/articles/awesome-image.png",
"image_large": "https://images.somedomain.com/CACHE/articles/5326a90dafc79cc7e6c5948660299d7b.png",
"image_medium": "https://images.somedomain.com/CACHE/articles/2903482490kdc7e6c5948660299d7b.png",
"image_small": "https://images.somedomain.com/CACHE/articles/8834dafc79cc7e6c5948660299d7b.png",
"image_tag": "https://images.somedomain.com/CACHE/articles/5326a90dafc79cc7e6c59asdsd9d7b.png",
"description": "An absolutely awesome description for an awesome article"
}

Now you can with ease fetch just the sizes you seem fit for a particular component you are building, or for any use-case really. That's perfect for serving thumbnails and images that adhere your design choices without compromising on quality of the image or speed of your application.

I hope you find the tutorial useful, and if you have any questions or input, just let me know in the comments below.

Freddie Freddie 4 years, 2 months ago 0
Login to Comment
No comments have been posted yet, be the first one to comment.
Query your Django REST API like a GraphQL API with Django RESTQL
Query your Django REST API like a GraphQL API with Django RESTQL
The hype around GraphQL in recent years has been hard to ignore for any web developer. In short, GraphQL is a query language and runtime for APIs, and it has taken the web with storm. GraphQL makes it possible for front-end developers to query data from a single API endpoint and retri...
How to Cache Django REST Framework with Redis
How to Cache Django REST Framework with Redis
Django REST Framework is an awesome package that will aid you in writing REST APIs faster with Django and Python. Though Django REST Framework has many strengths, performance out-of-the-box might not be one of them. However, there are many ways to fix that, and one of them is caching....
How to Rebuild Django-MPTT Tree Structure
How to Rebuild Django-MPTT Tree Structure
Most application utilize some sort of tree structure to managing data, in one form or another. One common use-case is nested categories. If you are using Django for your current project and are in need to implement tree structures, there is a big change you have come across Django-MPT...