Tony's Site

Storing photographs using Django

Introduction

I currently run a number of small websites using Django. I have a requirement for a small database of volunteers with a facility to upload and store photographs. The basic requirement is to:

As I wasn't sure how to do some of these I decided to experiment with a small prototype. This is not yet complete - the parts in green below are still to be achieved. The description below assumes knowledge of implementation of Django.

Django Configuration

I set up a simple model to store pictures as follows:

class Photo(models.Model):
   photo = models.ImageField(upload_to="photos")

In order for this to work a couple of entries are required in the Django settings:

MEDIA_ROOT = '/var/www/testsite/apache/media/'
MEDIA_URL = '/sitemedia/'

This defines a folder used for storage of static files and a url configured in Apache to point at that folder. The upload_to entry in the model defines a folder in MEDIA_ROOT that will be used to store the actual photos. The database only stores the file names. The user under which Apache runs needs to have write access to this - in may case www-data.

The Solution

The test site has a transaction consisting of three phases. Below lists what is included on each phase and describes some elements of how it is done. Parts in green are still to be completed.

Phase 1

  • Display a form with a single input field for a photograph.

This is straightforward. The basics of the template are:

<form action="/phase2" enctype="multipart/form-data" method="post">
<input type="file" name="photo" />
<input type="submit" value="Submit" />
</form>

Phase 2

  • Receive the input from phase 1
  • Extract the photograph
  • Store the photograph in the model
  • Display a new page including the photograph
  • Allow the used to crop the photograph to highlight head and shoulders.
  • Return coordinates defined by the cropping.

Although the documentation wasn't entirely clear on this receiving and storing the photograph was fairly easy. Relevant bits of Django documentation are here and here.

from test.models import Photo
session=request.session
uploadpic = request.FILES['photo']
newphoto = Photo()
newphoto.photo.save(uploadpic.name,uploadpic)
newphoto.save()
session['photoid'] = newphoto.id

When displaying a template in response to this the stored photograph can be access from the url newphoto.photo.url.

Phase 3

This stage involves image manipulation. I plan to use the Python Imaging Library (PIL) for this.

  • Receive the cropping coordinates.
  • Retrieve the original photograph.
  • Load the photograph into PIL.
  • Crop the photograph.
  • Resize the photograph to a standard size.
  • Save the updated photo in the model.
from PIL import Image
from StringIO import StringIO
from django.core.files.base import ContentFile
session=request.session
# Retrieve photo
pid = session['photoid']
newphoto = Photo.objects.get(id=pid)
# Load into PIL
newimage = Image.open(newphoto.photo)
# Resize the photo
newimage = newimage.resize((200,267),Image.ANTIALIAS)
# Save updated photo
picfile = StringIO()
newimage.save(picfile,"JPEG")
picfile.seek(0)
newphoto.photo.delete()
newphoto.photo.save("h%s.jpg"%pid,ContentFile(picfile.getvalue()))
newphoto.save()

I save the updated photo to a different name. Prior to this note the newphoto.photo.delete() line. Without this the old picture file would not be removed when the new one is saved.