Readers of this site (save those reading it through an aggregator) will notice the randomly rotating banner at the top of the page. I included the banner to add a little more color on the site, show off a few photos I have taken, and to give me an excuse to write a custom view in Python. Django made it easy.

In brief, here are the steps involved:

  • define a directory where the banners will live
  • set up the URLconf
  • create a view to handle the request and render the response
  • include the <img> tag in the template

The central decision I had to make was how the banners would be managed. My first inclination was to store the image information in a database and have them managed through Django’s admin interface. That seemed to be a bit overkill for my humble site, and would have required the creation of a model and the inclusion of the Python Image Library (to handle file uploads using the ImageField field type).

All I really need is a directory to house the banners, and then the banners could be added and deleted through my normal codebase update process (rsync over ssh, if you must know). Since I would like the ability to easily change this location, I create an entry in the project settings file, to be used by the view function:

# in settings.py
BANNER_DIR = os.path.join(os.path.dirname(__file__), 'static', 'images', 'banners')

This variable simply specifies an OS-independent file system path pointing to the directory where the images will reside.

Next, I add a URL to the URLconf, instructing requests for /images/banner/ to be handled by the specified view function:

# in urls.py
urlpatterns += patterns('',
    (r'^images/banner/$', 'stringify.weblog.views.banner'),
)

The view function is responsible for receiving the request, gathering a list of all the banner images from the aforementioned settings.BANNER_DIR directory, and randomly selecting one to return in the response:

# in weblog/views.py
def banner(request):
    import settings, glob, random, os.path
    from django.http import HttpResponse
    image_ext = None
    image_data = None
    image_dir = settings.BANNER_DIR
    ext_mimetypes = {
        'jpg': 'image/jpeg',
        'gif': 'image/gif',
        'png': 'image/png', }
    if os.path.isdir(image_dir):
        images = []
        for ext in ext_mimetypes.keys():
            paths = glob.glob(os.path.join(image_dir, '*.' + ext))
            images.extend(paths)
        if len(images) > 0:
            image = random.choice(images)
            image_ext = image.split('.')[-1]
            image_data = open(image, 'rb').read()
    return HttpResponse(image_data, mimetype=ext_mimetypes.get(image_ext))

Note the ext_mimetypes dictionary both limits the types of files served, and also provides a lookup for the mime type for the HTTP response. If I wanted to also serve, say, TIFF images, all I would have to do is add 'tif': 'image/tiff',.

With all the elements in place, all that is left to do now is to upload some images — all with similar dimensions — to the settings.BANNER_DIR directory, and include an <img> tag in a template somewhere:

<!-- in templates/weblog/base_site.html -->
<img id="banner" src="/images/banner/?{% now "YmdHis" %}" width="600" height="75" alt="" />

One last little bit of trickery involves the use of Django’s {% now %} template tag to append the current time to the end of the URL in the query string. This is an anti-caching measure to prevent browsers (IE in particular) from caching the URL and loading the same image each time. What good is a rotating banner if it does not rotate?