A more robust conditional get

3 views
Skip to first unread message

Ivan Sagalaev

unread,
Oct 19, 2007, 5:20:25 PM10/19/07
to django-d...@googlegroups.com
Hello!

A similar issue was raised on this list some time ago but as far as I
remember there wasn't any proposed solution. I think I have a good one.

I'm trying to solve a problem with the current implementation of
conditional get where ETag and Last-Modified are taken into account only
after a view finished working. This takes care of the client letting him
not to download a representation that's not changed but totally omits
the ability to save a server from a hard work of constructing the
representation. However it's often possible for the server to know if
the representation is not changed without actually producing it. For
example instead of constructing a whole forum page with latest posts one
can just check if If-Modified-Since sent by client is equal to the last
post update time.

As a solution I propose a view decorator taking as a parameter a
function calculating Last-Modified and/or ETag that takes care of all
the mechanic of checking request headers, returning 304 Not Modified
and setting response headers. It looks somewhat like this (with
last-modified):

@condition(lambda r, s: Forum.objects.get(slug=s).latest().time)
def forum(request, slug):
# ...

A working code can be checked out from my SVN repository[1].

I didn't file a ticket for this yest because I vaguely remember some
opposition to the whole idea of trying to optimize current conditional
get behavior. I'd like to raise this issue again and if it turns out
that people like the idea I'll happily wrap the code along with tests
and docs in Trac.

[1]: svn://softwaremaniacs.org/cicero/trunk/ (file conditional_get.py)

Jeremy Dunck

unread,
Oct 19, 2007, 6:32:39 PM10/19/07
to django-d...@googlegroups.com
On 10/19/07, Ivan Sagalaev <Man...@softwaremaniacs.org> wrote:
> As a solution I propose a view decorator taking as a parameter a
> function calculating Last-Modified and/or ETag that takes care of all
> the mechanic of checking request headers, returning 304 Not Modified
> and setting response headers. It looks somewhat like this (with
> last-modified):
>
> @condition(lambda r, s: Forum.objects.get(slug=s).latest().time)
> def forum(request, slug):
> # ...

Neat-o. License? If it's OK, I'll use it whether it goes into django
trunk or not. :)

Jeremy Dunck

unread,
Oct 19, 2007, 6:36:03 PM10/19/07
to django-d...@googlegroups.com
On 10/19/07, Ivan Sagalaev <Man...@softwaremaniacs.org> wrote:
> I didn't file a ticket for this yest because I vaguely remember some
> opposition to the whole idea of trying to optimize current conditional
> get behavior. I'd like to raise this issue again and if it turns out
> that people like the idea I'll happily wrap the code along with tests
> and docs in Trac.

See the comments here, in which there is some discussion on the
downside of if-mod and etag. Adrian weighs in to point out there are
things outside the known parameters that contribute to freshness.

I don't see that being a problem with this approach, though. You can
apply the decorator where useful...

http://www.tbray.org/ongoing/When/200x/2007/07/31/Design-for-the-Web

Malcolm Tredinnick

unread,
Oct 19, 2007, 9:26:00 PM10/19/07
to django-d...@googlegroups.com
On Sat, 2007-10-20 at 01:20 +0400, Ivan Sagalaev wrote:
> Hello!
>
> A similar issue was raised on this list some time ago but as far as I
> remember there wasn't any proposed solution. I think I have a good one.
>
> I'm trying to solve a problem with the current implementation of
> conditional get where ETag and Last-Modified are taken into account only
> after a view finished working. This takes care of the client letting him
> not to download a representation that's not changed but totally omits
> the ability to save a server from a hard work of constructing the
> representation. However it's often possible for the server to know if
> the representation is not changed without actually producing it. For
> example instead of constructing a whole forum page with latest posts one
> can just check if If-Modified-Since sent by client is equal to the last
> post update time.
>
> As a solution I propose a view decorator taking as a parameter a
> function calculating Last-Modified and/or ETag that takes care of all
> the mechanic of checking request headers, returning 304 Not Modified
> and setting response headers. It looks somewhat like this (with
> last-modified):
>
> @condition(lambda r, s: Forum.objects.get(slug=s).latest().time)
> def forum(request, slug):
> # ...
>
> A working code can be checked out from my SVN repository[1].

The decorator approach feels like a reasonable fit for a lot of cases
where the default isn't going to be a good fit. This isn't an area where
one-size-fits-all is appropriate because there are too many specific
considerations to take into account.

So, as an addition to the current behaviour, I'm probably +1 on
including this. There's a bit of common stuff we can factor out from
that code to avoid duplication with the middleware and other ETag
handling code people might want to write, but that's minor stuff.

Regards,
Malcolm

--
A clear conscience is usually the sign of a bad memory.
http://www.pointy-stick.com/blog/

Ivan Sagalaev

unread,
Oct 20, 2007, 3:49:39 AM10/20/07
to django-d...@googlegroups.com
Jeremy Dunck wrote:
> Neat-o. License? If it's OK, I'll use it whether it goes into django
> trunk or not. :)

Let's say it's BSD. This is a part of the tutorial on writing forum in
Django and I didn't think about wrapping it as a product. But if I did
it would be BSD usually :-)

Ivan Sagalaev

unread,
Oct 21, 2007, 7:23:32 PM10/21/07
to django-d...@googlegroups.com
Malcolm Tredinnick wrote:
> So, as an addition to the current behaviour, I'm probably +1 on
> including this. There's a bit of common stuff we can factor out from
> that code to avoid duplication with the middleware and other ETag
> handling code people might want to write, but that's minor stuff.

Here it is: http://code.djangoproject.com/ticket/5791

I wonder if any docs needed besides a docstring... I've placed the code
near require_http_method decorator which isn't documented either.

Reply all
Reply to author
Forward
0 new messages