Wednesday, March 24, 2010

Working with Images Using Django on Jython

If you've tried to use Django on Jython along with an ImageField, you know well that Django on Jython does not support this field. This is because the ImageField in Django relies on the Python Imaging Library (PIL). Jython does not support the PIL since it is C based, and there is not currently a version of the PIL that has been ported to Java.

That being said, how do we make use of images in Django on Jython? Since the ImageField is not usable from Django on Jython, we need to use an alternate method for uploading and displaying images. The following is a solution I've been using for one of my applications. This is certainly not a perfect solution, nor do I think we should modify Django on Jython to support this solution out-of-the-box. However, it works and gets the job done.

In order to use images with Django on Jython, you need to make use of the FileField. Since the FileField does not display in a template as an image, it is also a requirement to tweak the template which will be displaying the images with an ordinary "img" tag. Also, to make things work nicely, it is important to code a variable...we'll call it "image_src"...with the path to the image that will be displayed. This is done within your views in views.py. Of course, images will take the name attribute of your FileField, but you must prefix that name with the path to your web server. So my solution for this is to create another variable, say PHOTO_ROOT, in the settings.py and we will set it equal to the web server's MEDIA_ROOT location.

Lots of steps to make a usable image? Not really, it may seem daunting at first glance, but it does work easily once you've got it down.

Steps for using images with Django Jython:

1) Create a FileField in your model to contain your image information. Be sure to indicate where you wish the image to be uploaded to by specifying the "upload_to" attribute.

For example, in the following case the "images" directory which is specified by the 'upload_to' attribute exists directly under the MEDIA_ROOT root:

class MyTestModel(models.Model):
photo = models.FileField(upload_to='images', blank=True)


2) Create a variable within settings.py to contain the path to your web server's MEDIA_ROOT location. Please note that this will need to be changed when you deploy to different environments (ie: development or production).


PHOTO_ROOT = 'http://localhost:8000/site_media/'


3) Add a variable to your views through which the image path will be exposed. This variable will need to contain the PHOTO_ROOT you specified in settings.py, as well as the appended file.name for the FileField containing your image. Therefore, you will need to code a line in each view you wish to expose the image through.

In order to make your UI slick, it is a good idea to use a default image for any records that may not have an image uploaded. You can assign the path for that default image to your variable if your FileField does not contain anything.


# Be sure to import your settings file
from django.conf import settings
...
# This code contains relevant portions of a detail view for displaying or modifying
# a record
def detail(request, record_id=0):
...
record = get_object_or_404(MyTestModel, pk=record_id)
form = MyForm(instance=record)

# Check to see if the FileField (photo) contains anything
if record.photo:
image_src = '%s/%s' % (settings.PHOTO_ROOT, record.photo.name)
else:
image_src = '%s/images/nophoto.jpg' % settings.PHOTO_ROOT

...
return render_to_response('detail.html',
{'form':form,
'image_src':image_src})



4) Add an "img" tag to your template in order to display your image. You must also add the "form.photo" field to the template in order to have the ability to upload an image.



some_content
...


{{ form.photo }}

<img title="Photo"
src="{{ image_src }}"/>


...
more_content


That is basically it. When you view the record initially, the default image should appear. After an image is uploaded successfully, it should replace the default image.

No comments: