概要
Djangoのビューを実装するのに、関数で書く方法と、Viewクラスやその派生クラスを継承して必要なメソッドをオーバーライドする方法がある。
Djangoのオーソドックスな書き方ではクラスベースビューのListViewなどを利用し、コード量を減らすことが推奨されている。
ここでは関数による方法とViewクラスの継承クラスによる方法の2つを比較する。
基本形
テンプレートの準備
ビューからパラメーターを受け取り、単にそれを表示するテンプレートを準備する。ここではviewtestというアプリケーションを想定し、準備するテンプレートファイルはindex.htmlとする。
|
1 |
<p>Parameter: {{ parameter }}</p> |
関数によるビューの実装
views.pyの記述
アプリケーションディレクトリー下のviews.pyファイルに、indexビューを関数で定義する。ビューではテンプレートに渡すパラメーターを文字列'Hello!'としている。
|
1 2 3 4 5 |
from django.shortcuts import render def index(request): params = {'parameter': 'Hello!'} return render(request, 'viewtest/index.html', params) |
urls.pyの記述
アプリケーションのサブディレクトリーfunctionから、同じアプリケーションのindexビューへのルーティングを定義する。この例の場合localhost:8000/viewtest/functionのようにURLを指定し、ブラウザーでアクセスすることになる。
|
1 2 3 4 5 6 |
from django.urls import path from viewtest import views urlpatterns = [ path('function', views.index), ] |
ここでサーバー起動状態でブラウザーに先のURLを指定すると、ブラウザーに以下のように表示される。
|
1 |
Parameter: Hello! |
関数ビューの場合、GETを含むリクエストに対してurls.pyに従ってビューが呼び出され、その内容が実行される。
クラスベースビューによる実装
関数によるビューと同じ処理をクラスベースのビューで実装してみる。ここでは比較のために、関数ビューのコードを残してクラスベースビューのコードを追加していく。
views.pyの記述
クラスベースのビューは、Viewクラスやその派生クラス(ListViewなど)を継承し、getやpostなどのリクエストに対応したメソッドを記述する。ここではGETリクエストにのみ反応させるため、getメソッドを実装している。
|
1 2 3 4 5 6 7 8 9 10 11 |
from django.views.generic import View from django.shortcuts import render def index(request): params = {'parameter': 'Hello!'} return render(request, 'viewtest/index.html', params) class IndexView(View): def get(self, request): params = {'parameter': 'Hello!'} return render(request, 'viewtest/index.html', params) |
Viewクラスではgetメソッドは定義されていないが、Viewの派生クラスでGETメソッドでのリクエストがあるとViewクラスのhandlerが実行され、View.get()が実行される。そして派生クラスでget()を定義しているとこれがオーバーライドされたメソッドとして実行される。
参考:Django ViewではHttpメソッド名の関数を定義することができる
urls.pyの記述
クラスベースビューによるメソッドが呼び出されるようにアプリケーションのurls.pyにpath関数を追加する。
|
1 2 3 4 |
urlpatterns = [ path('function', views.index), path('class', views.IndexView.as_view()), ] |
関数ベースの場合はpath関数の第2引数に関数表現のビューモジュールを指定したが、クラスベースの場合はIndexViewの親クラスViewのas_view()メソッドを指定している。as_view()メソッドは内部関数view()を通してdispatchメソッドを返すので、結局パスが解決されるとdispatchメソッドが呼び出されることになる。
ここでサーバー起動状態でlocalhost:8000/viewtest/classなどとURLを指定すると、ブラウザーに以下のように表示される。
|
1 |
Parameter: Hello! |
URLパラメーターを含む場合
関数によるビューの実装
urls.pyの記述
URLパラメーターを含む場合、URLパターンに型名やパラメーター名を入れる。
|
1 2 3 4 5 6 |
from django.urls import path from viewtest import views urlpatterns = [ path('function/<int:parameter>', views.index), ] |
views.pyの記述
ルーティングで記述したパラメーター名をビュー関数の引数に指定し、これをテンプレートに渡す。
|
1 2 3 4 5 |
from django.shortcuts import render def index(request, parameter): params = {'parameter': parameter} return render(request, 'viewtest/index.html', params) |
ここでサーバー起動状態でlocalhost:8000/viewtest/function/1などとURLを指定すると、ブラウザーに以下のように表示される。
|
1 |
Parameter: 1 |
クラスベースによる実装
urls.pyの記述
URLパターンにURLパラメーターを記述する方法は関数の場合と同じ。クラスベースビューの場合はas_viewメソッドの実行結果を渡す。
|
1 2 3 4 5 6 7 |
from django.urls import path from viewtest import views urlpatterns = [ path('function/<int:parameter>', views.index), path('class/<int:parameter>', views.IndexView.as_view()), ] |
views.pyの記述
クラスベースビューの場合、getなどのメソッドの引数にパラメーターを指定する。引数の指定パターンは関数の場合と同じ。
|
1 2 3 4 5 6 7 8 9 10 11 |
from django.views.generic import View from django.shortcuts import render def index(request, parameter): params = {'parameter': parameter} return render(request, 'viewtest/index.html', params) class IndexView(View): def get(self, request, parameter): params = {'parameter': parameter} return render(request, 'viewtest/index.html', params) |
ここでサーバー起動状態でlocalhost:8000/viewtest/class/2などとURLを指定すると、ブラウザーに以下のように表示される。
|
1 |
Parameter: 2 |
GET/POST処理
関数によるビューの実装
テンプレートの準備
GETで表示されるページにフォームを追加し、送信先をfunctionサブディレクトリー、メソッドをPOSTとする。
|
1 2 3 4 5 6 |
<p>Parameter: {{ parameter }}</p> <form action="function" method="post"> {% csrf_token %} <input type="submit" value="送信"> </form> |
urls.pyの記述
今回のindexテンプレートはGET、POST両方のリクエストから呼び出されるため、functionサブディレクトリーのルーティング1つ。
|
1 2 3 4 5 6 |
from django.urls import path from viewtest import views urlpatterns = [ path('function', views.index), ] |
views.pyの記述
リクエストメソッドの違いはrequest.methodの文字列で判定して処理を分ける。GETリクエストの場合は1つ目のifブロックが実行され、テンプレートに文字列'GET!'が渡される。またPOSTリクエストの場合は2つ目のifブロックが実行され、テンプレートには文字列'POST!'が渡される。
|
1 2 3 4 5 6 7 8 9 10 |
from django.shortcuts import render def index(request): if request.method == 'GET': params = {'parameter': 'In function, GET!'} return render(request, 'viewtest/index.html', params) if request.method == 'POST': params = {'parameter': 'In function, POST!'} return render(request, 'viewtest/index.html', params) |
ここでサーバー起動状態でlocalhost:8000/viewtest/functionなどとURLを指定すると、views.index関数でGETに対応したifブロックが実行され、ブラウザーに以下のようにGET!と表示される。
|
1 2 |
Parameter: In function, GET! [送信]←ボタン要素 |
このページで「送信」ボタンを押すと、今度はviews.index関数でPOSTに対応したifブロックが実行され、ブラウザーにPOST!と表示される。
|
1 2 |
Parameter: In function, POST! [送信]←ボタン要素 |
クラスベースによる実装
テンプレートファイルの準備
POSTに対する処理を関数の場合と分けるため、送信先のURLのサブディレクトリーをclassとする。
|
1 2 3 4 5 6 |
<p>Parameter: {{ parameter }}</p> <form action="class" method="post"> {% csrf_token %} <input type="submit" value="送信"> </form> |
urls.pyの記述
GET/POSTに関わらず、classサブディレクトリーでのリクエストを受け取った場合には、IndexViewクラス(のインスタンス)に処理を渡すように定義。
|
1 2 3 4 5 6 |
from django.urls import path from viewtest import views urlpatterns = [ path('class', views.IndexView.as_view()), ] |
views.pyの記述
ルーティングで
|
1 2 3 4 5 6 7 8 9 10 11 |
from django.views.generic import View from django.shortcuts import render class IndexView(View): def get(self, request): params = {'parameter': 'In View class, GET!'} return render(request, 'viewtest/index.html', params) def post(self, request): params = {'parameter': 'In View class, POST!'} return render(request, 'viewtest/index.html', params) |
ここでサーバー起動状態でlocalhost:8000/viewtest/classなどとURLを指定すると、views.IndexViewクラスでオーバーライドしたgetメソッドが実行され、ブラウザーに以下のように表示される。
|
1 2 |
Parameter: In View class, GET! [送信]←ボタン要素 |
このページで「送信」ボタンを押すと、今度はviews.IndexViewクラスでオーバーライドしたpostメソッドが実行され、ブラウザーに以下のように表示される。
|
1 2 |
Parameter: In View class, POST! [送信]←ボタン要素 |
クラスベースビューの基本のまとめ
要点
基本のクラスベースビューの要点は以下のとおり。
- Viewクラスを継承したクラスを定義
- GETやPOSTなどに対応したメソッドを定義
- ルーティングでは、継承先のクラスの
.as_view()メソッドを渡す
views.pyの記述
django.views.genericパッケージのViewモジュールをインポートViewクラスを継承したクラスを定義getメソッド、postメソッドなどを定義- 第1引数は
self - 第2引数は
request - パラメーターがあればそれ以降
- 第1引数は
getメソッドの記述内容は、関数ベースの場合の内容と同じ- たとえば
render(request, 'target_page')
- たとえば
urls.pyの記述
urlpatterns属性のpath関数の第2引数でビュークラスを指定し、このときas_viewメソッドを指定する- たとえば
path('sub_dir', views_dir.MyViewClass.as_view())
- たとえば