DjangoのTemplateViewについて

##目的
DjangoのTemplateViewが何をしているかを把握しDjangoの理解を深める。

※個人的な解釈のため間違っていたらどなたか指摘いただけると幸いです。

##実際にソースを追ってみる

###【TemplateView】

```django.views.generic.base.py
class TemplateView(TemplateResponseMixin, ContextMixin, View):

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)
```
TemplateViewの中身はgetメソッドを実装しているだけ。
継承しているクラスを追ってみる。
　1. TemplateResponseMixin
　2. ContextMixin
　3. View

####1. TemplateResponseMixin

##### - render_to_responseを定義しているMixin

```django.views.generic.base.py
class TemplateResponseMixin:

    template_name = None
    template_engine = None
    response_class = TemplateResponse
    context_type = None
    
    def render_to_response(self, context, **response_kwargs):
        """
        TemplateResponseクラスを返すメソッド。
        引数に、リクエスト、テンプレート名、コンテキスト、
        テンプレートエンジン、**kwargsを渡している。

        setdefaultはpythonの組み込みメソッドで、
        指定したキーが無い場合、指定の値をデフォルトとして追加する。
        この場合、context_typeがなかったらself.context_typeをセット。
        """
        response_kwargs.setdefault('context_type', self.context_type)
        return self.response_class(
            request=self.request,
            template=self.get_template_names(),
            context=context,
            using=self.template_engine,
            **response_kwargs
        )

    def get_template_names(self):
        """
        テンプレート名をリストで返すメソッド。
        render_to_responseがオーバーライドされない限り呼ばれる。
        """
        ...
        return [self.template_name]
```
これはMixinというもので、何らかの機能のみが定義されたクラス。
※多重継承によって、複数のクラスで同じインスタンス変数などを使っていた場合、継承したクラスで問題が起きたりするため、多重継承する場合は、このような何らかの機能だけを定義したようなクラスを用いる事が多い。

####2. ContextMixin

##### - get_context_dataを定義しているMinxin

```django.views.generic.base.py
class ContextMixin:

    extra_context = None

    def get_context_data(self, **kwargs):
        """
        viewの指定がなければ、このメソッドを呼んだクラスをviewとして指定。
        """
        kwargs.sefdefault('view', self)
        if extra_context is not None:
            kwargs.update(self.extra_context)
        return kwargs
```
get_context_dataによって受け取ったキーワード引数を、テンプレートのコンテキストとして渡すデフォルトのMixin。

####3. View

##### - 全てのViewで継承される親クラス。そのため意図的にシンプルに書かれている。

```django.views.generic.base.py
class View:
    
    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    def __init__(self, **kwargs):
        """
        コンストラクターで、URLConfで呼ばれる。
        継承したViewインスタンスに対して、キーワード引数で渡されたものをセットする。
        """
        for key, value in kwargs.items():
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):
        """
        viewメソッドを返すメソッド。
        viewメソッドは、継承したクラスをインスタンス化し、dispatchメソッドで一致したメソッドを返す。

        ・検証
           1. http_method_names以外のメソッドだったら、TypeError
           2. 渡された引数をインスタンスが持っていなかったら、TypeError
        """
        ...


        def view(request, *args, **kwargs):
            """
            ・検証
            　1. as_viewを呼んだViewがrequestを持っていなかったらAttributeError
　　　　　　　　 →setupメソッドをオーバーライドしてsuper()を呼ばなかったりしたらこうなる。
            """
            self = cls(**initkwargs)
            self.setup(request, *args, **kwargs)
            ...
            
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs
        ... 

        return view

    def setup(self, request, *args, **kwargs):
        """
        全てのViewのメソッドで共有されるパラメータの初期化
        """
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.request = request
        self.args = args
        self.kwargs = kwargs

    def dispatch(self, request, *args, **kwargs):
        """
        ・検証
        　1. そのメソッドが定義されていなかった場合、許容メソッドリストに無いメソッドの場合エラーを返す。
        
         ➡ requestのメソッドが許容しているメソッドだったらそのメソッドを返す。
        """
  
        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)

   ...

```


### まとめ

<br>

__・Viewの指定__

urls.pyで、TemplateView.as_view()と宣言する事で、
　1. その指定したURLにリクエストが来た時のViewをTemplateViewに指定する。
　2. リクエストのメソッドに応じてTemplateViewのメソッドが自動的に呼ばれる。
という仕組みっぽい。

<br>

__・TemplateViewの処理の流れ__

TemplateViewでは、getメソッドが最初から定義されていて、その中では、
　1. get_context_dataメソッドにより、contextを取得。
　　➡ テンプレート内に埋め込んだりできるもので無くても表示出来る。このメソッドをオーバーライドして辞書でテンプレートに渡せばテンプレートで表示出来る。

　2. render_to_responseでTemplateResponseクラスを返す。その際、引数に
　　- リクエストクラス
　　- テンプレート名
　　- コンテキスト
　　- テンプレートエンジン
　　- kwargs
　　を渡す。
つまり、TemplateViewで指定されていない、__テンプレート名__だけ指定すれば、テンプレートを返すまでの流れは既に実装してくれている。


as_viewメソッドらへんが分かりにくかったので、次はそこらへんを調べてみる。