Djangoで405 Method not allowedをキレイに処理したい。
Django でHTTP STATUSの405を出したいと思って、 ソースとほんのり追いかけてみたよ。
django/http/__init__.py の380行目あたりに HttpResponseNotAllowed なクラスがあるんですが、 こんな感じになっていて permitted_methods 以外はセット出来ない様子。
class HttpResponseNotAllowed(HttpResponse):
status_code = 405
def __init__(self, permitted_methods):
HttpResponse.__init__(self)
self['Allow'] = ', '.join(permitted_methods)
これだと画面が真っ白になってしまうんじゃ? と思いながら試してみたら、案の定真っ白。
なら、 HttpResponse 使って status_code だけ405にしてあげたら素敵になるんじゃ? しかもHttp405とかってException作っておいて、 それを投げるように出来ればもっと素敵になるんじゃ? なんて安易な発想を実装してみた。
SumiTomohikoの日記 さんの 403 Forbiddenを表示するミドルウェア をかなり参考にさせて頂きました。
まずはExceptionを定義。 Http404を読み込んでるのは、どうせなら一緒にimportしたいってだけで、 他に意味は全くないっす。
# vim: fileencoding=utf-8 :
from django.http import Http404
class Http400(Exception):
pass
class Http403(Exception):
pass
class Http405(Exception):
pass
次にミドルウェアとその他もろもろの定義。名前はそれぞれ適当にそれっぽく。
# vim: fileencoding=utf-8 :
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
from django.template import loader, Context, RequestContext
from exceptions import *
def _bad_request(request, template_name='400.html'):
"""
HTTP STATUS 400を処理する。
"""
t = loader.get_template(template_name)
c = RequestContext(request, {})
return HttpResponseBadRequest(t.render(c))
def _forbidden(request, template_name='403.html'):
"""
HTTP STATUS 403を処理する。
"""
t = loader.get_template(template_name)
c = RequestContext(request, {})
return HttpResponseForbidden(t.render(c))
def _not_allowed(request, permitted_methods, template_name='405.html'):
"""
HTTP STATUS 405を処理する。
"""
t = loader.get_template(template_name)
# 要求されたメソッドと許可されているメソッドをテンプレートに渡す。
c = RequestContext(request, {
'REQUEST_METHOD' : request.method,
'PERMITTED_METHODS' : permitted_methods,
})
response = HttpResponse(t.render(c))
# status_codeの変更。
response.status_code = 405
# レスポンスヘッダに許可されているメソッドをセット。
response['Allow'] = ', '.join(permitted_methods)
return response
class HttpExceptionMiddleware(object):
"""
HttpなExceptionを処理する。
"""
def process_exception(self, request, e):
if isinstance(e, Http400):
return _bad_request(request)
if isinstance(e, Http403):
return _forbidden(request)
if isinstance(e, Http405):
return _not_allowed(request, permitted_methods=e)
return None
Http404はデフォルトで処理されるので、今回は見ない事に。 それぞれの処理をメソッドではなく関数にしてるのは、 どこか他でも使い回せるかなぁ?なんて浅はかな先読みでしかないです。
あとは、ココで作ったミドルウェアを settings.py の MIDDLEWARE_CLASSES に追加してやる。
MIDDLEWARE_CLASSES = (
'applications.http.middleware.HttpExceptionMiddleware', # <-- コレを追加。
...
)
これで views.py とかでHttp405とかを投げると、 決められたテンプレートでレンダリングしてくれる訳ですが、 リクエストメソッドを確認する為に、 毎回同じ様な処理を書くのがメンドクサイので、 Python の勉強も含めてデコレータも作ってみた。
強烈に参考にさせて頂いたのは Agent Ultra さんの RESTful Representations for Django Views 。
def restrict(*accepts):
"""
リクエストメソッドでフィルタリング。
"""
def decorator(fn):
def inner(request, *args, **kwargs):
if request.method not in accepts:
raise Http405, accepts
return fn(request, *args, **kwargs)
return inner
return decorator
実際使うときはこんな感じになる。
@restrict('POST', 'PUT')
def some_view(request):
"""
POSTかPUTしか許可されないビューになるよ。
"""
なかなかいい感じ。
期待した通りに動いてくれるし、
コード量も激減出来るし、かなり素敵 ![]()
ほぼパクりっぱなしだったけど、 色々勉強出来たのでやってみて良かった! 刺激を与えてくれた某 endless 氏と、参考にさせて頂いた方と、 それを探して来てくださった 常山 さんに激しく感謝!
- Posted at:
- 2007/10/24 00:30:36
- 0 Comments
- 1 TrackBack
- Trackback:
- http://humming.via-kitchen.com/2007/10/24/processing-more-clearly-405-on-django/trackback/
TrackBacks
[Django][Python][jQuery][その他]巡回 - 常山日記
Python温泉: [spa]Python 温泉へ持って行く課題 自分も今回の課題を決めておかないと Blog: Djangoで405 Method not allowedをキレイに処理したい。 Django tutorials, presentations and slides Fun with Beautiful Soup DjangoPaste 0.0 Edit inline with ImageField or F
- Created at:
- 2007/10/24 01:54:14
Comments
まだ登録されていません。