はじめてのDjango (3) 簡単なview関数とurlルーティング，および，urlからのパラメータ取得とtemplate

# はじめに

このドキュメントは，もともとはラボの新メンバー向けの入門テキストとして作成したもので，はじめてDjangoにふれる人にざっとその全体像をつかんでもらうことを狙っています．Djangoの日本語での参考資料も充実してきたので今さらという気がしないでもないですが，見直しを機にQiitaに移すことにしました．万が一でもどなたかの参考になれば幸いです．

説明のための具体例として，Djangoのオフィシャルチュートリアルにある投票アプリをとりあげています（が，説明上の都合で少しコードを追加，変更しているところもあります）．素人の独学がベースで，特に前半は公式チュートリアルをやってみた感想のような記事です（今回は全7回中の3回目）．

全体のコードはまとめて[GitHub](https://github.com/j54854/introDjango)に置きました．

## 変更履歴

- [2021/04/26] Djangoのバーションを3.2に更新し，それ基づいて内容を微修正しました．

# 簡単なview関数とurlルーティング

webアプリケーションでは，基本的にページを動的に生成します．すなわち，あるページがリクエストされるとそのたびに，そのページに必要なデータを生成するなどの処理を走らせます．この処理をview関数が担っています．

view関数は，リクエスト（HttpRequestクラスのオブジェクト）を受け取り，レスポンス（HttpResponseクラスのオブジェクト）を返します．

最初に，ごく簡単な例を見てみましょう．view関数はviews.pyの中に記述することになっていますので，このファイルを開いて，下記の内容を書き込みます．

```python
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world!")
```

この`index()`関数は，何も動的な処理は行わずに，単に`"Hello, world!"`という文字列だけを返しています．引数に指定されている`request`はHttpRequestクラスのオブジェクトです．戻り値が`HttpResponse()`の形式になっていることにも注意しておきましょう．

次に，このview関数で生成されたレスポンスを表すページが指定されたurlで表示されるようにします．この作業を，urlルーティングと呼びます．urlルーティングの情報は，urls.pyの中に記述することになっています．

urls.pyは，デフォルトの状態では内側のmysiteディレクトリの中にだけ存在しますが，ここはプロジェクト全体の情報を格納する場所なので，アプリケーション固有の情報はアプリケーションのディレクトリに格納しておいた方が便利です．そこで，pollsディレクトリの中にももう1つurls.pyという名前のファイルを作成することにしましょう．

そして，内側のmysiteディレクトリの中のurls.pyには，下記の内容を書き込みます．

```python
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]
```

また，pollsディレクトリの中のurls.pyには，下記の内容を書き込みます．

```python
from django.urls import path
from . import views

app_name = 'polls'

urlpatterns = [
    path('', views.index, name='index'),
]
```

`urlpatterns`のリストの中に指定されているのが，urlルーティングの情報です．`path()`の第1引数がアドレスの文字列で，第2引数がそのアドレスがリクエストされたときに起動するview関数，`name`は（後で説明するように）このアドレスを逆引きするための名前です．また，`include()`で，urlルーティングの処理を別ファイルに引き継ぐことができます．

上の例では，アドレスのホスト部分`http://lodalhost:8000/`の後に`polls/`という文字列が続くと，それ以降の処理をpollsディレクトリの方のurls.pyに引き継ぐようにしています．そして，それに続いて空文字列が現れた（ということは，アドレスの末尾に到達した）場合，views.pyファイルの中の`index()`関数を呼ぶという指定になっています．

また，polls/urls.pyの中で指定されている`app_name`は，上述の逆引きのための名前をアプリケーションごとに区別できるようにするためのものです（が，これについても下で説明することにします）．

これで作成したview関数に対応するページが表示されるはずです．開発用サーバを起動して，http://localhost:8000/polls/ にアクセスしてみましょう．

# urlからのパラメータ取得とtemplate

view関数はurlからパラメータを取得することもできます．質問項目のid番号を取得する例をみてみましょう．まず，viws.pyの末尾に，次の2つのview関数を追加します．

```python
...

def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)
```

どちらのview関数も，リクエストの他に，`question_id`という引数を受け取り，戻り値として返すレスポンスの文字列に埋め込んでいるのがわかります．polls/urls.pyを次のように更新して，この`question_id`という引数をurlから取得できるようにしてみましょう．

```python
from django.urls import path
from . import views

app_name = 'polls'

urlpatterns = [
    path('', views.index, name='index'),
    path('<int:question_id>/', views.detail, name='detail'),
    path('<int:question_id>/results/', views.results, name='results'),
]
```

アドレスの文字列の部分にある`<int:question_id>`が引数の型と名称を指定しています．その結果，urlルーティングの際に，この部分に現れるint型の値が，`question_id`という名前で取得され，対応するview関数に引数として渡されます．

結果を確認するために開発用サーバを起動して，http://localhost:8000/polls/1/ ，http://localhost:8000/polls/1/results/ にそれぞれアクセスしてみましょう．

ここまでは，veiw関数のレスポンスとしてごく簡単な文字列のみを返していましたが，一般には，html形式のデータを返すことになります．その際には，view関数の中にhtmlを生成する処理を記述すると煩雑になるので，それとは別にhtmlの構造だけをtemplateとしてあらかじめ用意しておき，その中にcontextと呼ばれるデータを埋め込んでレスポンスを作成するという手順を取ります．

簡単な例をみていきましょう．まず，上で作成したview関数`details()`を次のように修正します．

```python
from django.shortcuts import render

...

def detail(request, question_id):
    context = {'question_id': question_id}
    return render(request, 'polls/detail.html', context)
```

最後の行にある`render()`がレスポンスの作成を担当しており，その2つ目の引数が使用するtemplateを示しています．view関数の中で，まず`context`を辞書型のデータとして用意し，`request`とtemplateとともにこの`render()`に渡しているのがわかります．

これがtemplateを利用する際の典型的は流れになります．`render()`を利用するためには，それをあらかじめ`import`しておく必要があることに注意しましょう．

ただし，まだtemplateを作成していないので，このままではエラーになります．pollsディレクトリの中に，templates（複数形）という名前のディレクトリを作成し，さらにその中にpollsというディレクトリを作って，そこにpollsアプリケーションで使用するtemplateファイルを格納していきます．

今回作成するtemplateはdetail.htmlという名前のファイルです．所定の場所にこの名前のファイル（外側mysite/polls/templates/polls/detail.html）を作成し，下記の内容を書き込みましょう．

```html
<h1>Question #{{ question_id }}</h1>
<ul>
    <li>
        <a href="{% url 'polls:results' question_id %}">
            results
        </a>
    </li>
</ul>
```

templateは，通常のhtmlドキュメントの中に`{{ }}`や`{% %}`で挟まれたタグが追加された形式になっています．`{{ }}`は，基本的に，`context`として渡されたデータを挿入する際に用います．単に挿入するだけではなく，先頭の文字だけ大文字にするなど，簡単なフィルタも用意されています．

一方，`{% %}`は，何らかの処理を実行するためのタグです（後でみるように，if文やforループなどもあります）．上の例では，urlの逆引き処理を行ってリンク先のアドレスを作成しています（ここで用いているのが上のurlルーティングで指定した`app_name`とname属性で，`{% url 'app_name:name' 引数 %}`という形式になっています）．

templateで利用できるタグやフィルタの詳細は[ここ](https://docs.djangoproject.com/en/3.2/ref/templates/builtins/)に整理されています．

# おわりに

以上で3回目は終了です．[第4回](https://qiita.com/j54854/items/64ad3b7d2f50b5567e61)に続きます．