django - How to edit/manipulate uploaded images on the fly before saving

Sometimes you need to perform certain operations on user uploaded images before saving them in Django. These operations may include cropping images, rotating them, generating thumbnails or compressing them. I'll show you how to do that.

You'll need to have Pillow installed for that.

Sample model

Below is a sample model which has two fields - image and thumbnail.

# models.py

from django.db import models


class MyModel(models.Model):
    image = models.ImageField()
    thumbnail = models.ImageField()

Now let's say we want to auto generate thumbnails from the image uploaded by the user.

Function for generating thumbnails

We'll create a new function called make_thumbnail which will create thumbnails for the given image. Keep this in code wherever you like.

This code works for Django >= 1.7.

from io import BytesIO
from django.core.files import File
from PIL import Image


def make_thumbnail(image, size=(100, 100)):
    """Makes thumbnails of given size from given image"""

    im = Image.open(image)

    im.convert('RGB') # convert mode

    im.thumbnail(size) # resize image

    thumb_io = BytesIO() # create a BytesIO object

    im.save(thumb_io, 'JPEG', quality=85) # save image to BytesIO object

    thumbnail = File(thumb_io, name=image.name) # create a django friendly File object

    return thumbnail

Here's some explanation about the code:

  1. im.convert(RGB) is done to convert the image's mode to RGB. Because sometimes Pillow throws an error when we try to save an image in JPEG format if the image is a GIF with a limited palette.
  2. im.thumbnail(size) is a method of Pillow's Image class which scales the image to the given size while keeping the aspect ratio.
  3. thumbnail = File(thumb_io, name=image.name) creates a Django-friendly File object which we can use as the value for a model's ImageField.

Other than that, the code is fairly basic. This is just to give you an idea about manipulating images on the fly.

Calling the function from the model

And here's how you'd call the function from the model:

# models.py

# import the `make_thumbnail` function
from some_file import make_thumbnail

class MyModel(models.Model):
    image = models.ImageField()
    thumbnail = models.ImageField()

    def save(self, *args, **kwargs):
        self.thumbnail = make_thumbnail(self.image, size=(100, 100))

        super().save(*args, **kwargs)

That is it

You can adapt and modify the code to perform any operations you like on the images, for example crop them, or even apply Instagram like fancy filters.

It's up to you.