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