Make組ブログ

Python、Webアプリや製品・サービス開発についてhirokikyが書きます。

Django1.4のクラスベースビューにおけるHEADリクエストの処理について。

django.views.generic.base.TemplateViewなどのクラスベースビューの実装を見てみると、head()メソッドが書かれていないように見える。しかしHEADリクエストには対応してる、という話。

「TemplateViewはHEAD対応していない」的なお話を聞くことがあるから書いておく。

環境

Django 1.4

head()はたしかに実装されていない

class TemplateView(TemplateResponseMixin, View):
    """
    A view that renders a template.
    """
    def get_context_data(self, **kwargs):
        return {
            'params': kwargs
        }

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

https://github.com/django/django/blob/1.4/django/views/generic/base.py#L113

( ´゚д゚`)ナイワー

でもHEADリクエストには対応している

試しにお話してみる

% telnet hirokiky.vir 8000
Trying 192.168.56.101...
Connected to hirokiky.vir.
Escape character is '^]'.
HEAD / HTTP/1.0
Host: hirokiky.vir

HTTP/1.0 200 OK
Date: Tue, 25 Sep 2012 12:11:32 GMT
Server: WSGIServer/0.1 Python/2.7.1+
Content-Type: text/html; charset=utf-8

対応してますやん。

こんなかんじのを動かしてる。

url(r'^$', TemplateView.as_view(template_name='myapp/index.html')),

ちなみにGETで

% telnet hirokiky.vir 8000
Trying 192.168.56.101...
Connected to hirokiky.vir.
Escape character is '^]'.
GET / HTTP/1.0
Host: hirokiky.vir

HTTP/1.0 200 OK
Date: Tue, 25 Sep 2012 12:50:01 GMT
Server: WSGIServer/0.1 Python/2.7.1+
Content-Type: text/html; charset=utf-8



test


aaa

Connection closed by foreign host.

なんでheadが無いのに返ってくるのか

django.views.generic.base.Viewのas_viewを見れば分かる
as_viewは内部で定義しているviewという関数を返すんだけど、それは

       def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            return self.dispatch(request, *args, **kwargs)

https://github.com/django/django/blob/1.4/django/views/generic/base.py#L44

こうなってる。
getがあって、headがないクラスの場合にはheadにgetを設定してる
これでheadが無いときでもレスポンスを返してくれる。

そんで多分どっかのレイヤで
「HEADの場合はレスポンスのヘッダだけ返す」
ってなってくれてるんだと思う。

だから self.head = self.get しても問題ない。

じゃぁその「どっかのレイヤ」ってどこ?
というのはまだ分かってないから読んでいく。

ちなみに1.3では無い

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            return self.dispatch(request, *args, **kwargs)

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

https://github.com/django/django/blob/1.3/django/views/generic/base.py#L45

上記のように。

1.3 の場合はうまいこと実装してやるっぽい。


1.3については上記の記事とソースコード見ただけで、検証はしてない。

他のメソッドのときも対応できんじゃね

じゃぁheadだけじゃなくてpostとかでもいける気がしてしまう。
実際TemplateViewはPOSTメソッドでアクセスすると403が返ってくる。
同じ要領で実装できんじゃね

と思ったら

とのこと。
上記参考にして遊んでみます。