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_POST is a decorator which checks that the HTTP method of the request was POST, and returns HTTP 405 — “method not allowed” if it wasn’t.
require_GET is a decorator which checks that the HTTP method of the request was GET, and returns HTTP 405 if it wasn’t.
require_http_methods is a function which generates decorators, much like the user_passes_test decorator in django.contrib.auth which lets you specify any test you like for the user; require_http_methods takes 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.
Comments for this entry are closed. If you'd like to share your thoughts on this entry with me, please contact me directly.
It’s funny, I have your feed and djangosnippets’ feed in my RSS reader, and this snippet came right before your post. Very relevant.
Wasn’t there a proposal not long ago to include HTTP methods as part of the URLconf for easily implementing REST interfaces?
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.
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.
Thanks a lot. This is very helpful. I’ve been writing my own POST_Method_Required decorator until now!
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.
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).Without the typo above, so:
Ludvig, you probably want to read Malcolm’s article on this.