クラスベースの汎用ビューを使って高品質プログラミング

Django の汎用ビューの使い方を調べるために公式ドキュメントを読んだんですが、今更ながら Django1.3 で汎用ビューが関数からクラスに変わっていることを知りました。1.3 リリースは今年の3月23日だから、8か月近く知らなかったことになるかな。ハズカシイ。

関数版の汎用ビューもまだ使えるみたいですが、ドキュメントを見た感じたと、クラスベースの方が便利そう。


試しにいくつかのビューをクラスベースの汎用ビューを使って実装してみました。現在開発しているサービスのコードから抜粋。

from django.views.generic import ListView

class UserPostListView(ListView):
    # ビューが描画に使うテンプレートを指定
    template_name = "posts/post_user_list.html"

    # テンプレートで扱うときのクエリセットの名前を指定
    context_object_name = "post_list"

    # 1ページに表示するのは20個まで
    paginate_by = 20

    # ユーザーで絞り込んだクエリセットを返す
    def get_queryset(self):
        return Post.get_by_user(self.request.user)

    # テンプレートに渡すコンテキストにデータを追加
    def get_context_data(self, **kwargs):
        ctx = super(UserPostListView, self).get_context_data(**kwargs)
        ctx.update({
            "is_mypage": True,
        })
        return ctx

ListView を使っています。たったこれだけでページネーションに対応したビューが実装できてしまいました。あとはテンプレート書くだけ。


登録用の CreateView も使ってみました。

from django.views.generic import CreateView

class CreatePostView(CreateView):
    # ビューが描画に使うテンプレートを指定
    template_name = "posts/post_new.html"

    # 登録に使うフォームクラスを指定
    form_class = PostForm

    # 登録に成功したときのリダイレクト先を返す
    def get_success_url(self):
        return reverse("list_user_post")

    # ユーザーが入力したデータの検証に成功したら、
    # ユーザーデータを追加して保存。
    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())

    # テンプレートに渡すコンテキストにデータを追加
    def get_context_data(self, **kwargs):
        ctx = super(CreatePostView, self).get_context_data(**kwargs)
        ctx.update({
            "is_mypage": True,
        })
        return ctx

POST かどうか判断する if 文が無くてスッキリ。個人的に、if 文で GET か POST か判断して処理を分岐するやり方は、どうもしっくりきませんでした。Python で最初に使ったフレームワークが AppEngine の webapp だったので、HTTP リクエストをクラスの get や post メソッドに割り当てるやり方のほうが好み。


クラスベースの新しい汎用ビューでは、内部処理をところどころフックできます。汎用ビューをベースに、テンプレートを指定したり、リダイレクト先を指定したり、コンテキストに値を追加したりするだけで、やりたいことが実現できてしまうことが結構あります。Django の汎用ビュー便利すぎ。


「主キーでモデルを取得してテンプレートに表示する」みたいな超単純なビューならともかく、ちょっと複雑になりそうなら、まず汎用ビューが使えるか検討したほうがいいですね。そして、もし汎用ビューが使えなかったら、仕方ないから自分でゴリゴリ書く、と。バグの少ない高品質なサービスを作る一番の方法は、できるだけコードを書かないことですから。