Djangoチュートリアルの続き。
前回の記事はこちら。

Djangoには汎用ビューという、Web開発における基本的なビューを簡単に扱える機能が用意されている。

WordPressを例にとると、記事一覧ページ、記事詳細ページ、カテゴリや月別アーカイブページなどがあるが、Djangoの汎用ビューを使うとこれらと同様のビューを最低限のコード量で実装することができる。

今回は最新の質問5件を表示するindexページと、質問詳細detailページ、質問結果resultsページをそれぞれ汎用ビューに変換していく。

URLconfの修正

まずはpolls/urls.pyを以下のように修正する。

01
02
03
04
05
06
07
08
09
10
11
from django.urls import path
 
from . import views
 
app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

ビューの修正

次にpolls/views.pyを修正する。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic
 
from .models import Choice, Question
 
class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'
 
    def get_queryset(self):
        return Question.objects.order_by('-pub_date')[:5]
 
class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'
 
class ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'

IndexViewクラスにはListViewを、DetailViewとResultsViewにはDetailViewを使用している。

ListViewはオブジェクトのリスト表示を、DetailViewはオブジェクトの詳細ページの表示をそれぞれ担う。

少しだけコードを解説しておく。

まずはIndexViewクラスを見てみよう。

1
2
3
4
5
6
class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_question_list'
 
    def get_queryset(self):
        return Question.objects.order_by('-pub_date')[:5]

ListViewはデフォルトだと、app_name/model_name_list.htmlのテンプレートをレンダリングするようになっているが、template_name変数にファイルパスを指定することで任意のテンプレートを使うことができる。

context_object_nameにはテンプレートに渡すオブジェクト名を指定し、オブジェクト本体はget_querysetメソッドとして取得している。

次に、DetailViewとResultsViewだが、これらは処理としては全く同じことをしている。

1
2
3
4
5
6
7
class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'
 
class ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'

テンプレートに渡すモデルとしてQuestionを指定し、template_nameにはそれぞれ用意したテンプレートファイルのパスを指定する。

これでWebにおける基本的な一覧ページと詳細ページを、Djangoの汎用ビューとして置き換えることができた。