【Django】クラスベースビューの補足:ListViewの見えない処理と仕組みについて

概要

以下のListViewを使用したタスク一覧検索処理について、見えない親クラスの処理をざっくりと見える化して全体のどこの処理をオーバーライドしているのかをまとめた。

あわせて読みたい

概要 クラスベースビュー(class-based view)で一覧検索機能を作成したのでまとめた。 一覧検索機能は、Djangoがもともと用意しているListViewクラスを継承してを作成する。   前提 Djang[…]

【Django】クラスベースビューListViewを使用した一覧取得機能

 

ListView

ListViewの見えない処理をざっくりと見える化して、オーバーライドして実装する箇所は全体のどこにあたるのかを説明する。

ListViewの実装例

ListViewは例えば以下のように実装する。

todoapps.views.py


class TodoTopView(LoginRequiredMixin, ListView):
    """TODOリスト一覧表示"""

    # モデル
    model = models.Todo
    # テンプレート
    template_name = "todo/top.html"
    # 一覧データのkey名称
    context_object_name = "tasks"

    def get_queryset(self):
        """検索条件をオーバーライドする"""
        # ステータス0(未完了)かつ期日の昇順で取得
        return models.Todo.objects.filter(status=0).order_by("due_date")

 

GETリクエストの処理概要

細かい内容は割愛して、大きな処理の流れは以下となる。

【Django】クラスベースビューの補足:TodoTopViewの見えない処理の流れと仕組みについて
▲GET処理の流れ

 

解説

それぞれの処理について解説する。

全体の流れ

モデル名(model)に設定したテーブルオブジェクトを使用して一覧検索を行う。
一覧検索した結果をコンテキストに設定して、画面テンプレートとコンテキストを組み合わせたHTMLをレスポンスとして返却する。

 

dispatch()メソッド

ブラウザからのリクエストをもとに、get()メソッドまたはpost()メソッドの呼び出しを制御する。
今回はget()メソッドを呼び出す。

 

一覧検索処理

オーバーライドしない場合はモデル名に紐づくテーブルを全検索する。
今回はモデル名(model)にmodels.Todoを設定しているため、Todoクラスに紐づくテーブルが検索対象となる。
また、一覧検索処理をオーバーライドしており、ステータスが0(未完了)のデータを検索して期日の昇順でソートして取得している。

 

コンテキスト設定

検索結果をコンテキストに設定する。
デフォルトでは”object_list”をキーに、一覧データがコンテキストに登録される。
今回はcontext_object_nameフィールドに”tasks”を設定しているため、”tasks”にも紐づいて一覧データがコンテキストに登録される。
※コンテキストとは、画面にサーバーの値を表示させるための辞書データのこと

 

レスポンス返却

コンテキストとテンプレート名を組み合わせた画面を返却する。
今回はtemplate_nameに”todo/top.html”を設定しているため、”todo/top.html”とコンテキストを組み合わせた画面をレスポンスしている。

 

処理の補足

ListViewから呼ばれる親クラスについて、どんな処理を実行しているのか紹介する。

getメソッド

getメソッドは以下のような実装になっている。

BaseListView


def get(self, request, *args, **kwargs):	
    self.object_list = self.get_queryset()	
    allow_empty = self.get_allow_empty()	
	
    if not allow_empty:	
        # When pagination is enabled and object_list is a queryset,	
        # it's better to do a cheap query than to load the unpaginated	
        # queryset in memory.	
        if self.get_paginate_by(self.object_list) is not None and hasattr(	
            self.object_list, "exists"	
        ):	
            is_empty = not self.object_list.exists()	
        else:	
            is_empty = not self.object_list	
        if is_empty:	
            raise Http404(	
                _("Empty list and “%(class_name)s.allow_empty” is False.")	
                % {	
                    "class_name": self.__class__.__name__,	
                }	
            )	
    context = self.get_context_data()	
    return self.render_to_response(context)	

 

・一覧検索
・コンテキスト設定
・レスポンス返却

 

get_context_dataメソッド

get_context_dataメソッドは以下のような実装になっている。

BaseListView


def get_context_data(self, *, object_list=None, **kwargs):
    """Get the context for this view."""
    queryset = object_list if object_list is not None else self.object_list
    page_size = self.get_paginate_by(queryset)
    context_object_name = self.get_context_object_name(queryset)
    if page_size:
        paginator, page, queryset, is_paginated = self.paginate_queryset(
            queryset, page_size
        )
        context = {
            "paginator": paginator,
            "page_obj": page,
            "is_paginated": is_paginated,
            "object_list": queryset,
        }
    else:
        context = {
            "paginator": None,
            "page_obj": None,
            "is_paginated": False,
            "object_list": queryset,
        }
    if context_object_name is not None:
        context[context_object_name] = queryset
    context.update(kwargs)
    return super().get_context_data(**context)

 

・一覧取得
・コンテキスト設定(ページング含む)

 

スポンサーリンク