Requiring HTTP methods
Just a quick tip today: someone on IRC tonight was asking for an easy way to write a Django view which restricts itself to only allowing a specific HTTP method or methods. For example, a web-based API might want to only allow POST to specific views.
This is actually pretty easy to do with a set of decorators built in to Django, in the module django.views.decorators.http. Specifically, the fix for ticket #703 added three useful things to that module:
-
require_POSTis a decorator which checks that the HTTP method of the request wasPOST, and returns HTTP 405 — “method not allowed” if it wasn’t. -
require_GETis a decorator which checks that the HTTP method of the request wasGET, and returns HTTP 405 if it wasn’t. -
require_http_methodsis a function which generates decorators, much like theuser_passes_testdecorator indjango.contrib.authwhich lets you specify any test you like for the user;require_http_methodstakes a list of HTTP methods, and returns a decorator which enforces that the request uses one of those methods.
Also in that module is the decorator conditional_page, which provides helpful support for conditional GET; it has the same effect as django.middleware.http.ConditionalGetMiddleware, but as a decorator which only applies to a single view.
These have all been a part of Django for a couple years now, but unfortunately came in at a time when we weren’t quite as strict about requiring new functionality to include documentation before being checked in, so the official docs are somewhat lacking for these. I’ve opened a ticket (#6181 for those who are interested) for that, and if nobody else beats me to it I’ll work on it the next time I have a chance.
December 11, 2007
#
It’s funny, I have your feed and djangosnippets’ feed in my RSS reader, and this snippet came right before your post. Very relevant.
December 11, 2007
#
Wasn’t there a proposal not long ago to include HTTP methods as part of the URLconf for easily implementing REST interfaces?
December 11, 2007
#
Hi James, I’m actually that someone from IRC :-)
This is very cool information, but the original question I was asking is basically what Justin is saying. It would be useful to have something like:
(r’^do_stuff$’, GETHandler=my_app.views.do_stuff, POSTHandler=my_app.views.do_other_stuff )
Obviously, with a cleaner and better thought out interface but following that basic idea.
December 11, 2007
#
The general pattern people seem to use is not to write a view function, but instead to write a class, with methods corresponding to what you want to do on various HTTP methods, and have the class be the callable the URLConf routes to. The class can then decide which of its own methods to use to handle the request.
December 11, 2007
#
Thanks a lot. This is very helpful. I’ve been writing my own POST_Method_Required decorator until now!
December 12, 2007
#
Leo, James,
I thought it was something simpler like have method=POST in the urlconf, so that you’d have:
url(r’^save’, my_app.views.save, method=POST)
What I like about this is that just by looking at the URLConf you can see what’s going on, and the url dispatcher can throw a 405 without decorators.
The callable class is interesting too, because you can a base class handle the routing based on the request method and throw 405s if the subclass doesn’t implement the correct method.
December 17, 2007
#
I have an idea. With devel, you can now provide functions in the URLconf, thus my idea:
Wouldn’t be very hard to write the
http_demodulatorfunction either, its signature would be something along the lines ofhttp_demodulator(default, **kw).December 17, 2007
#
Without the typo above, so:
December 17, 2007
#
Ludvig, you probably want to read Malcolm’s article on this.