ハッピーメリークリスマス。 この記事はDjangoアドベントカレンダーの18日目の代打です。
概要
- Djangoには関数ベースのビューと、クラスベースのビューの2種類がある
- クラスベースの方は利用する時に
as_view
というクラスメソッドからviewオブジェクトを生成している - これは一体何してるんですか? というメモを雑に残す。
前提
-
Djangoのビューはドキュメントにも書いてある通り以下の条件を満たす必要がある
-
requestオブジェクトを(第一引数として)受け取る
-
callableである
-
responseオブジェクトを返す
A view is a callable which takes a request and returns a response.
refs https://docs.djangoproject.com/en/2.0/topics/class-based-views/
- Django 1.3 以前は関数ベースで書くのが普通だったが、なるべくコードを書かずに再利用可能なビューを作るためにクラスベースのビューが導入された。
as_view クラスメソッド
例えば以下のような関数ベースビューがあるとする
from django.http import HttpResponse, HttpResponseNotAllowed
def myview(request):
if request.method == 'GET':
return HttpResponse('Hello, World!')
return HttpResponseNotAllowed('GET only accept')
これと等価なクラスベースビューを作ると下記のようになる
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request, *args, **kwargs):
return HttpResponse('Hello, World!')
myview = MyView.as_view()
- この
myview = MyView.as_view()
のmyview
は実態は関数である。 -
as_view
は Djangoのビューの条件を満たす関数 を作り出しているだけである
as_view を使わずにクラスベースビューを使う
たとえば as_view
を使わずにクラスベースビューを使おうとすると下記のようになる。(この例自体に意味はない。)
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request, *args, **kwargs):
return HttpResponse('Hello, World!')
def myview(request, *args, **kwargs):
view_obj = MyView()
view_obj.request = request
view_obj.args = args
view_obj.kwargs = kwargs
return view_obj.dispatch(request, *args, **kwargs)
- クラスベースビューは最初の起点が
dispatch
メソッドとなる -
dispatch
メソッド は リクエストメソッド を判定して、その リクエストメソッド と同じ名前のメソッドが実装されていたらそれを実行する。 - つまり
request.method == 'GET'
だったらMyview.get
を実行するということ -
dispatch
が実装されてるメソッドに応じて処理を自動的に分岐してくれるので、関数ベースでやっていた時のように自分で分岐を書かなくても良い。
# こんな感じで分岐を書かなくても良いという話
def myview(request):
if request.method == 'GET':
# code for GET
if request.method == 'POST':
# code for POST
if request.method in ('PATCH', 'PUT'):
# code for PATCH or PUT
if request.method == 'DELETE':
# code for DELETE
return HttpResponseNotAllowed('Not accept method {}'.format(request.method))
Djangoの該当コード
実際にDjangoがview関数を生成している部分をgithubのコードから抜粋して確認する
# refs https://github.com/django/django/blob/master/django/views/generic/base.py#L49
@classonlymethod
def as_view(cls, **initkwargs):
# 〜 省略 〜
# 自分自身をインスタンス化するビュー関数を生成してreturn してる
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
# 〜 省略 〜
return view
-
as_view
は 自ら(=cls
) をインスタンス化してdispatch
メソッドを実行するような関数(=view
)を生成してreturn
しているのがわかる。
まとめ
-
クラスベースビューの
as_view
は Djangoのビューの条件を満たす関数を生成しているだけ。極論を言えば条件満たせばなんでもいい。 -
クラスベースビューの基本的な機能は、リクエストメソッドに応じた処理の自動分岐を提供することである
-
それをベースにテンプレートをレンダリングする機能を加えたり、CRUDの機能が追加されたのが他の
views.genrice
群 -
例) TemplateView, RedirectView, CreateView, etc...
以上おわり