Views層でFBVとCBVを書く時、なぜ同じ結果が得られるかの疑問はないでしょうか。そしてUrls層でルーティングを設定する場合もCBVとFBVの書き方が変わりますよね? その原因をソースコードに合わせ、見ていきたいと思っています。
CBVの根本的なところに入るための入口はどこにあるか、そしてどの流れでgetやpostを実行するのかを見てみましょう!
入口
path('books1/', views.Books.as_view())
as_view()を入り口とし、後ろのソースコードを追跡します。
はい、では、@classonlymethod
はviews.Books.as_view()と書く理由で、クラスメソッドのことです。
as_viewメソッドはviewが戻り値になり、このviewは実際にas_view内部の関数のことを指しています。
view関数の戻り値はdispatch関数なので、次はdispatchを追跡します。
ここで、ちょっと補足しますが、pythonの継承関係について。このdispatchの例で言うと、dispatchを実行したい場合、最初はクラスのobject(インスタンス)から探します、そしてobjectが所属したclass、って継承されたclassの流れでdispatchを探します。今回はobjectにdispatch方法がないため、自然にViewクラスのdispatch方法を実行します。*
dispatch
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
これはViewクラスのdispatch方法です。引数について、selfはobjectのこと、requestはurlsで与えられたrequestのことです。
if文のところから見てみます。request.method.lower()は例えばPOSTやGETを小文字化するため、self.http_method_namesはなんやろ??
実はViewクラスで定義され、
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
となります。
次に、if分が成立したら、ようするにrequest methodがこのリストに入っているのであれば、次を実行します。
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
getattrを使って、self(objectのこと)の中に、POSTやGETを小文字化した方法はあるかどうか。あるの場合はhandler変数に与え、なかった場合はself.http_method_not_allowedがhanlder変数に与えます(self.http_method_not_allowedはデフォルト値と考えてもいいだと思います))。
そしてdispatch方法に戻り、戻り値をチェックしてください。
return handler(request, *args, **kwargs)
なんと!思った以上より分かりやすくて、単純にhandlerがreturnされただけ!
まとめると、as_viewから入り、dispatch方法を実行し、帰ってくるのはgetやpost方法になります。
まとめ
CBVは非常に重要です、特にDjango RestFrameWork上に大きいな役割を果たしています。また、DRFは実際、DjangoのViewを継承されていますので、DRFの理解を深まるためにはCBVの実行の流れも理解する必要があるだと思っています。
それほど詳しい説明ではないですが、最後まで見ていただきありがとうございました。