【Django】Webアプリ入門 Part3 テンプレートでHello,World

#はじめに
この記事シリーズでは、Python、JavaScript歴1年の大初心者がどうにか頑張ってWebアプリを作ろうとする過程を克明に描き出したいと思います。
なるべく公式ドキュメントやいろいろなサイトを調べて間違いのないようにしますが、これは違うんじゃない？と思ったら是非コメントをください！！
**ほかのプログラマ・エンジニアの方の生の声をいただくことは初心者にとっては貴重な学習の機会になります！！**

#Part3でやること
[前回](https://qiita.com/sun-narumi/items/3533b2590479078ef31a "Pre")の記事では開発環境を構築し、各ファイルの役割について確認しました。
今回の記事からは、いよいよコードを書いていきます。
今回はその最初ということでHello,Worldを表示させることをやってみたいと思います。

#HTMLファイルを表示させる仕組み
いつでも、誰に対しても表示が変わらないようなHTMLファイルを公開するときは、
URLでWebサーバーとディレクトリ名やファイル名を指定して、
そのWebサーバーがそのディレクトリ内にあるファイルを返すことによって
クライアントにHTMLファイルを見せています。
しかし、表示を動的に変えたいときは、(JavaScriptを使えばある程度何とかなるものの)
同一のファイルを返すことのみでは対応できません。

Djangoはどうやって動的にHTMLファイルを表示しているのでしょうか。
DjangoではURLで指定されるのはディレクトリでなく、**View関数**です。
特定のURLによって呼び出されたView関数の戻り値をもとに、クライアントにHTMLファイルが返されます。
その際のURLとView関数の対応付けは、プロジェクトフォルダの直下の同名のフォルダ内のurls.pyというファイルに記述します。

#実装1
実際にコードを書いてみましょう！
(以下ではプロジェクト名をmy_projectとし、アプリ名をmy_appとします。)
まずはView関数を作成します。my_appディレクトリのviews.pyに以下を記述します。

```python:my_app/views.py
from django.http import HttpResponse

def index(request):
  return HttpResponse("<h1>Hello,World</h1>")
```

View関数は上のように、requestというHttpRequestオブジェクトである引数を受け取ってHttpResponseオブジェクトを返します。
HttpRequestオブジェクトはリクエスト情報をプロパティとして持つオブジェクトであり、
HttpResponseオブジェクトは、インスタンス作成時に指定した引数の文字列からなるHTMLファイルを表します。
次にmy_project/my_projectフォルダ内のurls.pyにURLとView関数の対応を書きます。

```python:my_project/urls.py
from django.urls import path

from . import views

urlpatterns = [
  path('my_app/',views.index),
]
```
こうすることでURLのうちのディレクトリ部分を/my_app/とするとviews.indexが呼び出されるようになります。
他のURLとView関数を登録したいときは同様にpath関数を使って,
`path("ディレクトリ名",関数名)`として`urlpatterns`に追加するだけです。

反映されているか確認してみましょう。
ターミナルでmy_projectフォルダに移動し、以下を入力します。

```:ターミナル
python manage.py runserver
```

このコマンドにより、Djangoの開発用サーバーを立ち上げることができます。
実行後に出てくるターミナル画面を参考に、localhost上からアクセスしてください。
Hello,Worldと表示されましたか？

#実装2
先ほどはmy_project/my_projectフォルダのurls.pyに直接path関数で
'my_app'とmy_appのindex関数を結びつけました。
しかし、アプリケーションやその内部のURL-Views対応関係が増えた時を考えてみてください。
すべて一か所に書くとごちゃついてしまい、名前の衝突が起きるかもしれません。
そこで各アプリケーションごとにURL-Views対応関係を表すファイルを作成し、
my_project/urls.pyでその関係を引っ張ってくることにします。

my_appフォルダにurls.pyを作成します。そして次のように書きます。

```python:my_app/urls.py
from django.urls import path

from . import views

urlpatterns = [
  path('',views.index),
]
```
そして先ほどmy_projectのurls.pyに書いたコードを一度消し、次のように書きます。

```python:my_project/urls.py

from django urls import path,include

urlpatterns = [
  path('my_app/',include('my_app.urls')),
]
```

こうすることで、my_app/urls.py ファイルで指定したURL-View関数対応関係は、
my_app/ディレクトリとview関数の対応関係としてmy_project/urls.pyに反映されます。

#実装3
HttpResponseをコンストラクタとして用い、
その引数でHTMLファイルを作成して返させるのは簡単です。
しかし、HTMLファイルが長くなると、
views.pyに延々とHTMLファイルの中身を書くことになります。
それはやめたいので外部にファイルを作成して、
View関数でそれを引っ張ってこれるようにしましょう。
そのためにMTVのTにあたるTemplateを使います。
TemplateファイルをHTMLファイルのように書いていき、
View関数がそれを読み込むことにします。

まずは下準備としてmy_project/settings.pyファイルのINSTALLED_APPSリストに
作成したアプリケーション情報を追加します。

```python:my_project/settings.py
INSTALLED_APPS = [
  'my_app.apps.MyAppConfig',
  ...
]
```
各自で作ったアプリケーションファイルのapps.pyに記述してあるクラスを、
上のようなドット区切り形式で書いてください。
テンプレートファイルは、my_app下にtemplatesフォルダを作り、
その下にmy_appフォルダを作ってから、その直下に作ります。
index.htmlというファイルを作る場合は、
`my_app/templates/my_app/index.html`という場所に作ります。
そのファイルにたとえば以下のように記述します。

```html:index.html
<!DOCTYPE html>
<html lang="ja" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>こんにちは</title>
  </head>
  <body>
    <h1>Hello,World</h1>
  </body>
</html>
```

次にView関数からこのファイルを読み込んで、その内容をもとにHttpResponseオブジェクトを返させます。my_app のviews.pyに、以下を記述します。

```python:my_app/views.py
from django.template import loader
from django.http import HttpResponse

def index(request):
  template = loader.get_template('my_app/index.html')
  return HttpResponse(template.render({},request))
```
再び`python manage.py runserver`を実行してみてください。
Hello,Worldと表示されるはずです！
loader.get_templateメソッドを使えばtemplateフォルダの下にあるテンプレートファイルを読み込めます。
その後、その戻り値オブジェクトのrenderメソッドを使うことで、
テンプレートをHttpResponseオブジェクト化できます。
template.renderメソッドの第一引数でテンプレートファイルに渡す変数の辞書を渡すのですが、
それは次回、モデル定義をするときに一緒に扱います。

このテンプレートをレンダーする流れはよく使うため、ショートカットが用意されています。
上のコードと下のコードは同じ結果になります。

```python:views.py
from django.shortcuts import render

def index(request):
  return render(request,'my_app/index.html',{})
```

少し簡単になりましたね！

#まとめ
今回はviews.pyで関数を定義し、urls.pyでマッピングすることによって、Hello,Worldを出力しました。
次回はモデルを作ってみようと思います！