Now ETagging Right!
17Apr2007 [webprog]
Am now handling etags right! Django already takes care of the messy business - caching generated views and sending the appropriate etags, so if a view doesn't change, the browser shouldn't have to download it again.
macosxpeter:~ peter$ wget -S http://wintermute.com.au/
--19:44:57-- http://wintermute.com.au/
=> `index.html'
HTTP request sent, awaiting response...
HTTP/1.1 200 OK
Content-Length: 21112
ETag: 3290c8e891866e8b1b0884e3a3820b7e
Content-Type: text/html; charset=utf-8
Length: 21,112 (21K) [text/html]
macosxpeter:~ peter$ wget -S --header='If-None-Match: 3290c8e891866e8b1b0884e3a3820b7e' http://wintermute.com.au/
--19:45:53-- http://wintermute.com.au/
=> `index.html.1'
HTTP request sent, awaiting response...
HTTP/1.1 304 NOT MODIFIED
Content-Type: text/html; charset=utf-8
19:45:54 ERROR 304: NOT MODIFIED.
But the etags weren't doing anything before, as I was generating random references to the banner image and to album photos on every load, so the view would change. I've now written a handy little 'randoms' app instead. Now the html for each page doesn't change - it just points to /random/banner.jpg
and to, eg, /random/photo.jpg?1
through ?4
. Those point to ordinary django views that deliver the contents of a random banner or photo. So the etag on those image references will change, but not on all the html pages, and that should make a real difference, as there's rarely much real change on most of the pages round this site...
The Django code, for anyone interested
Create a django app in the usual manner; this one is called randoms
(I tried random
until I realised it kept conflicting with the standard Python library random
); you can lose the models.py
file as this just pulls in other models...
Note that my setup differs from the usual advised by Django's docs, in that I have the folder where all my apps sit on the Python path. What this basically means is that I don't have to keep putting my_project.
before all my app calls, as hey, that violates DRY (though, true, it would've let me call the app random
, so I'm not going to argue this point). So if you're using the default setup, remember to drop a my_project.
into a bunch of the imports.
And of course, after creating the randoms
app, you'll want to include it in your INSTALLED_APPS
, and include this line in your project's urls
module:
(r'^random/', include('randoms.urls')),
urls.py
:
from django.conf.urls.defaults import *
urlpatterns = patterns('randoms.views',
(r'^banner.jpg$', 'banner'),
(r'^album-(?P<album_id>\d+).jpg$', 'album'),
(r'^photo.jpg$', 'photo'),
)
views.py
:
from django.conf import settings
from django.http import HttpResponse
import os, random
from photos.models import Photo,Album
def banner(request):
#return a random from the banners folder
banner_path = settings.MEDIA_ROOT + 'banners'
dir_list = os.listdir(banner_path)
file_list = []
for file in dir_list:
index = file.rindex(".")
if(file[index:] == '.jpg'):
file_list.extend([file])
rand = random.choice(file_list)
return HttpResponse(open(banner_path + '/' + rand,'rb',0).read(),'image/jpeg')
def album(request,album_id):
#return a random thumb from the given album
photos = Album(album_id).photos.values('filename')
photo = random.choice(photos)['filename']
photo_path = settings.PHOTO_ROOT + 'thumbs/' + photo
return HttpResponse(open(photo_path,'rb',0).read(), 'image/jpeg')
def photo(request):
#return a random thumb
photos = Photo.objects.values('filename')
photo = random.choice(photos)['filename']
photo_path = settings.PHOTO_ROOT + 'thumbs/' + photo
return HttpResponse(open(photo_path,'rb',0).read(), 'image/jpeg')
I've got a lot in here; obviously you can pick and choose between the various views, but there are probably a few useful bits in here.
def banner
:
This view, called with /random/banner.jpg
, returns the contents of a random image stored in a path of your choosing; I just created a banners
folder under the MEDIA_ROOT
, though it could easily live outside the webroot. It loops through the folder, looking for .jpg
s, picks one at random, reads it in (open(path).read()
) and outputs it... Django's HttpResponse
is usefully flexible, passing 'image/jpeg'
to it means it'll serve the response up with the appropriate mimetype (so the browser has no way of knowing the image was generated).
def album
:
This one hooks into my Album
model. The idea is that it returns a random image from the given album, so I call this with /random/album-N.jpg
, where N is an album's id. (I haven't put the necessary checks in to make sure that N exists, but there may be circumstances where you'd want to do that.) This view grabs a list of files associated with the given album (photos
is a ManyToManyField
), and returns one at random. The only weird thing here is settings.PHOTO_ROOT
, which is a setting I use on this site for my photos
app - I use it because I keep a number of photo files outside of the webroot, so the MEDIA_ROOT
setting wasn't enough.
Update
Made a little tweak to make the code work on my Windows box; the open
call needs a switch to tell it not to buffer ('rb',0
); cf random on windows
« The Roots, Live at the Enmore :: Photos with location clouds »
Related [webprog]
- None of these seem to get in the way (17May2010)
- IE6 and 7 on OSX (20Sep2008)
In which I run IE 6 and 7 on OSX; the entire process using free software - Random on Windows (15May2007)
In which I am baffled by the mystery that is Windows, and once more wooed by the ease with which one can make Python work, even there - Now ETagging Right! (17Apr2007)
In which I stop fighting the framework and let Django handle ETags the right way - Semantics and Style :: Markup for Dialogue (30Dec2006)
- Winter with Django (02Dec2006)
- Drop that double-u-double-u-double-u-dot (08Nov2005)
- Blog/Search (07Oct2005)
- Converting Relative to Absolute links in PHP (preg_replace) (21Sep2005)
- Think You’re Fighting Spam? (14Sep2005)
- BBC backstage access (12May2005)
- funky google trick (28Sep2004)
- The name of this class, ‘abc’, conflicts with the name of another class that was loaded, ‘abc’ (28Jun2004)
- The Altar Of Reason (10Jun2004)
- Domain.com.au Feedback (17May2004)
- aligned with evil (11May2004)
- flash gallery thingy (08Apr2004)