【Django】002. テンプレートの利用

前回はDjangoでロケットを飛ばすところまで見ていきました。
[前回記事：【Django】001. (Djangoでの) Webページの基本](https://qiita.com/ys_dirard/items/8de36ceac13a9f4a2879)

今回はDjangoのテンプレート (htmlファイル) について見ていきます。

今回も以下の本を参考にしています。

https://www.shuwasystem.co.jp/book/9784798062419.html

## テンプレートとは？

表示する内容を操作できるHTMLファイル (枠 / 素みたいなもの)

ビューからデータを渡してそれを追加で処理して表示すしたりことができる。

![https://it-biz.online/wp-content/uploads/2023/07/image-4-1024x539.png](https://it-biz.online/wp-content/uploads/2023/07/image-4-1024x539.png)

https://it-biz.online/python/template/

## 【準備】アプリケーションの登録
※以下のコマンドで```hello```というアプリケーションを作成したとする。
```sh
python manage.py startapp hello
```

```settings.py```の```INSTALLED_APPS```に```hello```を追加する。

```python:settings.py
INSTALLED_APPS = [
    "django.contrib.admin",
    ...(略)...
    "django.contrib.staticfiles",
    "hello", # 追加
]
```

```INSTALLED_APPS```に追加しておくことで、Djangoのテンプレート機能が```hello```を検索できるようになるようです。

## テンプレートの作成

### テンプレートの作成場所

```hello```アプリケーションのテンプレートは
「django_app(プロジェクト)/hello/templates/hello」
に作成します。

つまり、```hello```アプリケーションフォルダの中に```templates```フォルダを作成し、その中にさらに```hello```フォルダを作成します。

※helloの中にhelloがある奇妙な構成ですが、これが基本的な構成らしいです。

### index.htmlの作成
```django_app(プロジェクト)/hello/templates/hello```フォルダに```index.html```というファイルを作成します。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ title }}</h1>
    <p>{{ msg }}</p>
</body>
</html>

```

```title```と```msg```は枠として生成しておき、後でDjangoから値を渡して表示します。

### urlspatternの修正

```hello```アプリケーションの```urls.py```を以下に修正する (ない場合は作成し、プロジェクトの```urls.py```からルーティングするようにしておく)

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

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

```

### index関数の修正

```hello```アプリケーションの```views.py```を修正する。

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

def index(request):
    params = {
        "title": "Hello/Index",
        "msg": "this is sample page.",
    }
    return render(request, "hello/index.html", params)

```
先ほど作成したテンプレートに対してrequestとテンプレートで枠と設定しておいた変数の値を渡しています。

### ページにアクセスする
```sh
python manege.py runserver
```
でサーバーを起動し、```http://127.0.0.1:8000/hello/```へアクセスします。

すると以下のようにちゃんと表示されるかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594896/a727f867-514f-266d-44e8-346925285325.png)

テンプレートに渡した```title```と```msg```も無事に表示されていることがわかります。

## 複数ページの移動

今回は```index.html```を使いまわして2つのページを表示させてみます。

### index.htmlの変更

```django_app(プロジェクト)/hello/templates/hello```フォルダの```index.html```を変更します。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ title }}</h1>
    <p>{{ msg }}</p>
    <p><a href="{% url goto %}">{{ goto }}</a></p>
</body>
</html>

```
ページを移動できるようにリンクを追加しています。


### views.pyへの追記

```hello/views.py```を以下のように変更する。

```python:hello/views.py
from django.shortcuts import render
from django.http import HttpResponse

def index(request):
    params = {
        "title": "Hello/Index",
        "msg": "this is sample page.",
        "goto": "next",
    }
    return render(request, "hello/index.html", params)


def next(request):
    params = {
        "title": "Hello/Next",
        "msg": "This is another page.",
        "goto": "index",
    }
    return render(request, "hello/index.html", params)
    
```
```goto```変数の値でお互いを行き来できるようにしています。

### urlspatternを修正する

```hello```アプリケーションの```urls.py```を以下に修正する

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

urlpatterns = [
    path("", views.index, name="index"),
    path("next", views.next, name="next"),
]

```

### ページにアクセスする
```sh
python manege.py runserver
```
でサーバーを起動し、```http://127.0.0.1:8000/hello/```へアクセスします。

すると以下のようにちゃんと表示されるかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594896/d8e94bf4-88bc-16e3-543f-c0bcac65dda1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594896/10b67036-962c-bac2-2b69-f116a551081e.png)

リンクをクリックするとお互いを行き来できていることがわかります。

## {{ }}と{% %}って何？

### {{ }}はテンプレート変数

{{ }}は変数を括弧内に入れることで、変数をレンダリングできる。

例：
```
<h1>Hello {{ firstname }}, how are you?</h1>
```

変数は先ほど使用した例のようにrender時に渡すことが可能。

また以下のテンプレートタグ内で作成した変数も利用可能。

例：
```
{% with firstname="Tobias" %}
   <h1>Hello {{ firstname }}, how are you?</h1>
{% endwith %}
```

### {% %}はテンプレートタグ

{% %}はDjangoのテンプレートに用意されている特別な動きをするタグ。

今回の「url」は
{% url 名前%}
の形で記述することで指定した名前のURLが書きだされます。
ここでの名前とはurlspatternで指定したnameのことです。

```python:hello
urlpatterns = [
    path("", views.index, name="index"),
    path("next", views.next, name="next"),
]
```

他にも
```{% if ... %}```
```{% else %}```
```{% endif %}```
```{% for ... in ... %}```
```{% endfor %}```
等、様々なものが用意されています。

## 静的ファイルの利用

HTMLからロードするスタイルシートファイル、JavaScriptファイル、イメージファイル等をあらかじめ準備するのはどこに配置すればよいか？という話です。

静的ファイルは各アプリケーションの「static」フォルダ (なければ作成) に配置します。

style.cssというスタイルシートファイルを作成する場合は、
「django_app(プロジェクト)/hello/static/hello/css」
に作成します。
※これも冗長な構成な気もしますが、このような構成が一般的？なようです。

### style.cssを記述する
では実際にstyle.cssを記述します。

```css
body {
    color: gray;
    font-size: 16pt;
}

h1 {
    color: blue;
    opacity: 0.2;
    font-size: 36pt;
    margin-top: -20px;
    margin-bottom: 0px;
    text-align: right;
}

p {
    margin: 10px;
}

a {
    color: blue;
    text-decoration: none;
}

```

### index.htmlを修正する

index.htmlから先ほど作成したstyle.cssを読み込むようにします。

```html:index.html
{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{{ title }}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'hello/css/style.css' %}">
</head>
<body>
    <h1>{{ title }}</h1>
    <p>{{ msg }}</p>
    <p><a href="{% url goto %}">{{ goto }}</a></p>
</body>
</html>

```

以下で性的ファイルを利用できる準備をし、
```
{% load static %}
```
以下のように記述します。
```
href="{% static 'hello/css/style.css' %}"
```

ページにアクセスすると以下のようにcssが反映されていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594896/f422e6d5-a37e-e5e3-1f64-f114149aa0c8.png)


## Bootstrapの使用

Bootstrapというスタイルシートフレームワークを使用すると (デザイン初心者でも) 簡単にそれなりにいい感じのページを作成できます。(私はそれでもまだまだです…泣)

### index.htmlの修正

hello/index.htmlを以下に修正する。

```html:index.html
{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{{ title }}</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">

</head>
<body class="container">
    <h1 class="display-4 text-primary mb-4">{{ title }}</h1>
    <p class="h5">{{ msg }}</p>
    <p class="h6"><a href="{% url goto %}">{{ goto }}</a></p>
</body>
</html>

```

ページにアクセスすると以下のようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594896/784bd793-c615-4c64-0c16-f65bafa7f89f.png)

cdn.jsdelivr.netはCDN (Content Deliber Network) と呼ばれるサービスを提供するサイトです。

CDNを使用することでローカルに準備しなくてもネット経由でサービスを使えるということです。

リンクが長いですが、以下のサイトの「CDN経由でインクルードする」からコピーでOKです。

https://getbootstrap.jp/

### Bootstrapのクラス

先ほどの使用例からBootstrapのクラスが使用されている箇所を抽出すると以下になります。

```html
<body class="container">
    <h1 class="display-4 text-primary mb-4">
    <p class="h5">
    <p class="h6">
```

様々なクラスが準備されていますが例としては以下の表のような感じです。
|クラス|概要|
|-|-|
|h数字|テキストの大きさと太さの設定<br>h1~h6までで\<h1>~\<h6>タグに相当|
|display-数字|タイトル等のフォントとサイズの設定<br>display1~display-6まであり、数字が大きくなると文字が小さくなる。|
|text-数字|text-primaryなどで、テキストカラーの設定|
|m場所-数字|マージンの設定。<br>場所はt, b, l, r, x, yで上下左右と水平垂直方向を表す。<br>数字は1~5とautoがあり、数字が大きいほどスペースが広くなる。|
|p場所-数字|パディングを設定するもの。<br>マージンと同様に使用可能。|

大きさや場所を持つパターンは「クラス名 + 場所 + 数字」が基本で、色は追加で指定のように複数のクラスも組み合わせて使えそうです。多分便利！

クラス数多すぎる問題なので、欲しい機能が出てきたときに適宜探していきたいと思います。