🎃

DjangoのListViewに関して

2024/08/23に公開

DjangoのLivewViewのまとめ

すぐに忘れてしまうので、LivewViewについて備忘録としてまとめておく

公式サイトのLivewViewの説明

https://docs.djangoproject.com/ja/5.1/ref/class-based-views/generic-display/#listview

ListViewのコード

GitHubのListViewのコードです。バージョン5.1です

https://github.com/django/django/blob/3.1/django/views/generic/list.py

ListView

ListViewはDjangoの組み込みViewです。ListViewを継承したViewにおいて、オブジェクトのリストを表示するために利用します。テンプレートに複数のオブジェクトを保持するQuerySetをわたします

簡単に言うと、指定したモデルクラスの一覧を表示します

前提のモデル

以下のモデルで利用します。以下のカラムを保持します

name, hp, mp, type, birthday

models.py
from django.db import models


class Monster ( models.Model ) :
  class Meta:
    db_table = "monster"
    
  TYPE_CHOICES = (
      (1, "炎属性"),
      (2, "水属性"),
      (3, "闇属性"),
  )

  name = models.CharField(
      max_length=100
  )

  hp = models.IntegerField(
      default=0
  )

  mp = models.IntegerField(
      default=0
  )

  type = models.IntegerField(
      choices=TYPE_CHOICES
  )

  birthday = models.DateField(
    verbose_name="birthday",
  )

  created_at = models.DateTimeField(
    auto_now_add=True,
  )
  
  def __str__(self):
    return self.name

簡単なListView

最小構成ではないですが、基本形です

  • 「model」はモデル名として「Monster」を指定します。未設定の場合、「queryset」を指定するか、「get_queryset」メソッドのオーバーライドが必要です
  • template_nameではテンプレートファイルを指定します。デフォルトでは、「モデル名_list.html」になります。アプリ名とモデル名でディレクトリ分割したいのでディレクトリで区切ります
  • orderingは一覧表示の並びを指定します。何順でもよいですが、ここでは単純にidの昇順にします
  • ページングを10件にします
  • テンプレートで利用するquerysetは初期設定で「object_list」です
views.py
from django.views.generic import ListView
from .models import Monster

class MonsterListView(ListView):
  model = Monster
  template_name = "study/monster/list.html"
  ordering = "id"
  paginate_by = 10

テンプレートファイル

対応するテンプレートファイルです。

  • base.htmlを作成して、継承します
  • django_bootstarap5を利用します
  • Bootstrap5でスタイリングします
  • 一覧データを保持するquerysetの変数名は「object_list」です
  • 一覧のURL:study:monster_list
  • 新規作成のURL:study:monster_create
  • 更新のURL:study:monster_update
study/monster/list.html
{% extends "base.html" %}

{% load django_bootstrap5 %}

{% block title%}{{ title }}{% endblock %}

{% block content %}
<div class="container mt-4">
    <h2 class="mb-4 p-2 bg-primary text-white">Monster List</h2>
    
    <div class="mb-3">
        <a href="{% url 'study:monster_create'%}" class="btn btn-primary">新規作成</a>
    </div>
    
    {% bootstrap_pagination page_obj %}
    <table class="table table-bordered table-hover">
        <thead class="table-dark">
            <tr>
                <th>ID</th>
                <th>NAME</th>
                <th>HP</th>
                <th>MP</th>
                <th>Type</th>
                <th>Birthday</th>
                <th>詳細</th>
                <th>更新</th>
            </tr>
        </thead>
        <tbody>
            {% for o in object_list %}
            <tr>
                <td>{{o.id}}</td>
                <td>{{o.name}}</td>
                <td>{{o.hp}}</td>
                <td>{{o.mp}}</td>
                <td>{{o.get_type_display}}</td>
                <td>{{o.birthday}}</td>
                <td><a href="{% url 'study:monster_detail' o.id %}"class="btn btn-primary">詳細</a></td>
                <td><a href="{% url 'study:monster_update' o.id %}"class="btn btn-primary">更新</a></td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
    {% bootstrap_pagination page_obj %}
</div>
{% endblock %}

querysetを指定する

model, orderingを指定しないで、querysetを指定します。querysetで取得したい一覧を指定します。QuerySetを返す処理を指定します。同時に並び順も指定します。ここでは、全件を取得していますが、filterを利用して、絞り込むことも可能です。また、select_relatedなどを利用して、結合することも可能です。ただし、querysetには、1行の処理しか記述できません

views.py
class MonsterListView(ListView):
  template_name = "study/monster/list.html"
  queryset = Monster.objects.all().order_by("id")
  paginate_by = 10

get_querysetをオーバーライドする

model, querysetを指定しないで、get_querysetメソッドをオーバーライドします。より自由度の高い処理を記述可能です

views.py
class MonsterListView(ListView):
  template_name = "study/monster/list.html"
  paginate_by = 10
  
  def get_queryset(self):
    qs = Monster.objects.all().order_by("id")
    return qs

コンテキストにデータを渡す

get_context_dateメソッドをオーバーライドすることで、コンテキストに追加データを渡すことができます。つまり、テンプレートで利用するデータを指定します

views.py
class MonsterListView(ListView):
  model = Monster
  template_name = "study/monster/list.html"
  ordering = "id"
  paginate_by = 10
  
  def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context["title"] = self.__class__.__name__
    return context

継承元クラス

以下のクラスを継承しています

django.views.generic.list.MultipleObjectTemplateResponseMixin
django.views.generic.base.TemplateResponseMixin
django.views.generic.list.BaseListView
django.views.generic.list.MultipleObjectMixin
django.views.generic.base.View

メソッドの実行順序

setup()
dispatch()
http_method_not_allowed()
get_template_names()
get_queryset()
get_context_object_name()
get_context_data()
get()
render_to_response()

Discussion