社内チャットで出た質問。GETパラメータによって呼び出すビューを変えたい場合はどう書くとよいか。
クラスベースのビューを書くと割ときれいに書けるんじゃないかな、という話。
まずは素直に書いてみる。
def index(request): action = request.GET.get('action', '') if action == '': return view_default(request) elif action == 'abc': return view_abc(request) raise Http404
まあ、1回しか使わなくて特に変更も多くない、呼び出すビューの数も少ないというならこれでも良いのだけど、たとえば呼び出すビュー50個とか100個になってくるとメンテするのが大変になってくる。
djangoのviewはcallableであればよいので、クラスベースのビューを作って、そこにカスタムのビューを登録していく、という風にしてみる。
core/views.py
# coding:utf8 from django.http import Http404 class ClassBaseViews(object): """ クラスベースのビュー 以下のようなビューを簡単に作れます。 http://example.com/?action=アクション名 挙動をいろいろ変えたい場合は、ClassBaseViewsを 継承して__call__などをオーバーライドするとよいかも。 """ def __init__(self): self.views = {} def __call__(self, request, *args, **kwargs): action = request.GET.get('action', '') if action in self.views: return self.views[action](request, *args, **kwargs) raise Http404 def register(self, view, name=''): self.views[name] = view base_views = ClassBaseViews()
こうするとbase_views(request)のように使えるので、urls.pyは次のように書ける。
urls.py
urlpatterns = patterns('', (r'^$', 'core.views.base_views'), )
あとはbase_views.registerを使ってビュー関数を登録すればよいのだが、楽をするためにdjango adminのautodiscoverのようなものを実装してみたりした。詳細はソース参照。
登録する場合は各アプリケーションディレクトリにaction_view.pyを作って、その中でbase_views.registerを呼ぶ。
from django.http import HttpResponse from core import base_views def hello_view(request): return HttpResponse('Hello world!') base_views.register(hello_view)
上の例の場合、registerでnameを省略しているため、 http://example.com/ もしくは http://example.com/?action= でアクセスできることになる。
from django.views.generic.simple import direct_to_template from core import base_views from app2.forms import MyForm def show_form(request): return direct_to_template(request, 'app2/show_form.html', {'form': MyForm()}) base_views.register(show_form, 'form1')
この場合は、 http://example.com/?action=form1 となる。
クラスベースのビューは再利用、拡張をしやすいし、アプリを分割する上でも使えるので便利。