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