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?