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

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

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

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

URLconfの修正

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

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を修正する。

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クラスを見てみよう。

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だが、これらは処理としては全く同じことをしている。

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の汎用ビューとして置き換えることができた。