ゴミ箱の中のメモ帳

まだ見ぬ息子たちへ綴る手記

DjangoのViewがクラスベースになっていた(過去形)

少し思い出話をしよう。

Djangoを使い始めたのは1年と少々前になる。現在の会社に入ったのが去年の4月だが、それから空き時間で触り始めたのがきっかけになる。

当時はDjangoは1.4になっていたが、日本語訳されたDjangoのドキュメントはDjango1.0のものしか無かった。現在はDjango1.4のドキュメントの日本語訳が進められているが、Djangoの日本語サイトは現在もまだDjango1.0のドキュメントにリンクが張られている。日本語訳は完成しておらず誤字も多いが、これからDjangoを始めようと思っている方はDjango1.4のドキュメントを読んだほうがいい。Django1.0は現在のバージョンと互換性がない部分も多く、現在のDjangoではチュートリアルを進めることはできない。

ちなみに、現在の安定版はDjango1.5.2で、既にDjango1.6b2が出ているので近いうちにDjango1.6がリリースされるだろう。そうなると、Django1.4のサポートは終了してしまう。8月中にDjango1.6はリリース予定となっているので、そうなると現在翻訳を進めているDjango1.4のサポートが終了する。ブログにはDjango1.4のサポートは多少延長するかもしれないという記述はあるが、多少というのはいつくらいになるかわからないし、結局そう長くないだろう。

そんなこんなで英語の読めない私はDjango1.0のドキュメントを読んでDjangoを勉強した。そして上に書いている通りチュートリアルが動かなくて悩みに悩んだ。途中からDjango1.4のドキュメントを読むようになったのだが、1.0と1.4がごちゃごちゃになって正しい知識はないかと思う。

その一つが今しがた気づいた、DjangoのViewがクラスベースになっているという事だ。


まず、DjangoMVC(Model,View,Template)ではなくMVT(Model,View,Template)という概念を採用しており、それぞれを簡単に説明すると以下のようになる(私の認識)。

概念 役割
Model ORMでRDBの1つのテーブルと1つのPythonクラスが対応している。RDBとデータの制限をデザインする。
View HTTPリクエストを引数に取り、HTTPレスポンスを返す関数。モデルのデータをテンプレートに渡したりと、どのデータをユーザに見せるかを記述する。
Template Viewで取り出したデータを表示する形式(HTMLやXML等テキストであれば自由)を記述する。どうデータをユーザに見せるかを記述する独自のテンプレート言語を採用。
(Controller) 一般に言うところの、URLとViewを結びつけるコントローラはURLディスパッチャが担当する。

Viewの役割にあるように、Viewの処理は関数が担当していた。これは非常に不便で、同じような処理もユーティリティ関数にまとめるかデコレータを使う必要があった。今は不便だと言っているが、1時間前までは関数による処理でも非常に便利だと思っていた。だが、先程Viewがクラスで記述するように変更になっているという事を知り、クラス化による利便性を知ってしまったので関数が不便に思えるようになった。

現在はDjango1.5.2を使っているのだが、クラスベースに変更しているという事に気づかなかったという理由はいくつかある。

  • Djangoを始める際に読んだドキュメントが1.0であったため、Viewにクラスが導入されていないかった。
  • 現在の日本語訳ドキュメント(Django1.4)でもチュートリアルには関数ベースのViewの記述であり、クラスベースのViewは別ファイルのドキュメントにまとめられている。
  • Djangoを始めたのが1.4であったため、変更点のチェックが漏れていた。
  • 現在も関数ベースがサポートされている

クラスベースが導入されたのがDjango1.3になるため、リリースノートを見ていなかった。Django1.0からDjango1.4のドキュメントに飛び級で移動したのが大きな原因で、かつ、Django1.4のドキュメントのチュートリアルでは現在も関数ベースのViewで記載されている。これなら疑いもせず関数ベースかと思ってしまっていた。


クラスベースに変わっているのに気がつかなかった言い訳はこの程度にしておいて、関数ベースからクラスベースに変わって非常に便利になった。詳しくはクラスベース汎用ビューのドキュメントを読んで欲しい。いかに便利かがわかる。

私は今までViewの関数でGETとPOSTの処理を毎度毎度馬鹿みたいに分岐していた。

def sample( request):
    if _is_GET( request):
       pass

    form = SampleForm( request.POST)
    if form.is_valid():
        pass
    else:
        pass

    return _r2r( request, "sample.html", { "form": form})

見てもらえばわかると思うが、"_is_GET()"や"_is_POST()"というユーティリティー関数を用意し、POST処理を行う全ての関数でこの分岐を行なっていた。これが非常に冗長であった。新しいクラスベースのViewではこれだけでも簡単に解決されている(一例)。

class Smaple( View):
    def get( self, request, *args, **kwargs):
        pass

    def post( self, request, *args, **kwargs):
        pass

他にも、データを追加するフォームを持ったViewやテンプレートを表示するだけのView等、よく利用する汎用Viewを少数(ドキュメントにこう記述されている)付属してくれている。

class Sample( CreateView):
    template_name = "sample.html"
    form_class = SampleForm

    def form_valid( self, form):
        self.object = form.save( commit=False)
        self.object.user = self.request.user
        self.object.save()

        return redirect( self.get_success_url())

GETとPOSTの処理を分岐しているView関数があれば、それだけでもクラスベースに変更する価値はあるかと思う。本当にクラスベースは便利だ。ユーティリティー関数もクラスにまとめて多重継承して使うように変更した。


結果、Django便利。


Django×Python (LLフレームワークBOOKS)

Django×Python (LLフレームワークBOOKS)