見出し画像

【ソースコード付き】Django テンプレート 使い方まとめ

今回はDjango テンプレートについて解説していきます。

多くの方はテンプレートについて「HTMLファイルを表示させるためのもの」とざっくり全体を理解しているものの、「何ができて、何ができないか」詳しく理解されている方は少ないかと思います。

今回の記事を読んでいただけると「テンプレートでこんなことできたんだ!」と何かしら気付きを得られると思います。

1. テンプレートの概要

テンプレートが何か簡単に説明すると、「ビューからの変数をHTMLファイルに埋め込むためのシステム」です。

Djangoではテンプレートの裏側で動いているエンジンとして「DTL(Djnago Template Language)」が使用されています。DTLの代表的な代替テンプレートエンジンとしてJinaja2等使用可能ですが、Djangoではデフォルト設定されているDTLの使用が推奨されいています。

◆テンプレートの主な機能
・ビューから受け取る変数の表示{{  }}を使う)
・テンプレート上でロジックの制御、機能拡張{% %}を使う)

テンプレートの主な機能は上記になります。

◆テンプレートの特徴
・「{ }」「%」「|(パイプ)」等を使用し、変数表示やロジック制御
・Python風な記法ができる
・Pythonのように変数定義や複雑なロジックは書けない
・モジュールのimportはできない

テンプレートの特徴は上記になります。

具体的な使い方について以降で詳しく解説していきますが、まずはテンプレートの設定方法について解説していきます。

2. テンプレートの設定方法

テンプレートの設定として、「どこにテンプレート(HTML)ファイルがあるのか」Djangoに知らせる必要があります。

設定はsettings.pyで行います。

settings.py ※django3前提

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

INSTALLED_APPS = [
   ...,
   ...,
]

TEMPLATES = [
   {
       'BACKEND': 'django.template.backends.django.DjangoTemplates',
       #DIRSのリスト内に記入する
       'DIRS': [BASE_DIR / 'templates'],
       'APP_DIRS': True,
       ...
   },
]

記入する場所は1点だけです。'DIRS'のリスト内に上記のようにBASE_DIR / 'templates'と記入します。意味としてはBASE_DIRの中にあるtemplatesディレクトリをdjangoが読みにいきます。

BASE_DIRはサンプルコード上段の部分から来ており、基本はmanage.pyがあるディレクトリになります。したがってBASE_DIRの直下に'templates'ディレクトリを作成してください。

ディレクトリのイメージは以下です。

plusit                        #プロジェクトディレクトリ
├── config                    #設定ディレクトリ
│   ├── __init__.py
│   ├── settings.py
    ...
├── 〇〇app                    #アプリディレクトリ
│   ├── __init__.py
    ...
├── templates                 #htmlファイル用ディレクトリ
│   ├── base.html
│   ├── 〇〇.html
    ...
└── manage.py

設定は以上になります。

※Django2を使用の方は、settings.pyの記載方法が若干異なるので以下をご参考ください。

ここからはテンプレートの具体的な内容について解説していきます。

3. 変数について

テンプレートでは、コンテキストに格納された変数を表示することがきます。コンテキストはビューから渡された変数のことで、views.pyでのように設定します。

コンテキストイメージ(views.py)

from django.shortcuts import render
from django.contrib.auth.models import User

def contextfunc(request):
   ...
   #コンテキストのvalue部分
   user = User.objects.all()
   #{}内がコンテキスト
   return render(request, sample.html, {'user':user} )

コンテキストは、上記{}内で設定します。サンプルコードからもわかる通りコンテキストには辞書型の情報が格納されています。

3.1 コンテキスト内の変数表示方法

ここからは記法について詳しく解説していきます。

{{ 変数名 }}

#例
{{ user }} #モデル等で定義された__str__の結果(オブジェクト名)が表示
{{ user.username}} #ユーザーネームが表示
{{ user.0.username}} #0番目のユーザーネームが表示

ビューで設定したコンテキストを上記のように使用します。変数名が先ほど辞書型で設定したkeyの部分にあたります。{{ 変数名(コンテクストkey) }}とすることで画面上でコンテキストvalue部分を表示させることができます。

「変数名.モデルで設定したフィールド名」とすることでより詳細な情報を表示することができます。また上記のように「変数名.数字.モデルで設定したフィールド名」とすることで(数字)番目に取得できた値が表示されます。

3.2 フィルタによる表示内容の加工

変数表示の{{ 〜 }}の内側にロジックを書いて加工することはできませんが、Djangoには「フィルタ」という仕組み用意されていて、フィルタを使うことで文字列の長さを表示したり日時のフォーマットを変えたりすることができます。

具体的には以下のような使い方します。

{{ 変数名|フィルタ名 }}
{{ 変数名|フィルタ名:"引数" }} #引数を
{{ 変数名|フィルタ名1:"引数"|フィルタ名2:"引数" }}
※「|」の前後にはスペース可だが、「:」の前後にはスペース不可

フィルタは「|(パイプ)」を使って表現します。フィルタによっては「:」を使って引数を取ることもできますし、複数のフィルタをつなげて書くこともできます。

具体的なフィルタの種類については以降で解説していきます。

djangoではかなりの数フィルタが用意されているので、使用頻度の高い以下を解説していきます。

・default(デフォルト表示)
・length(文字列長表示)
・safe(エスケープ無効化)
・date(日時フォーマット)
・linenumbers(行番号付き)
・urlize(リンク変換)
・upper/lower(大文字/小文字に変換)
・timesince(経過時間の表示)

◆default(デフォルト表示)
変数の値がNone、0、False、[]
などの場合に指定した文字列を表示することがきます。例えば値がNoneの場合は、そのままNoneと画面に表示されてしまうので回避するために使用されます。

{{ value|default:"" }} #空欄

上記のように使用すると、仮にvalueがNoneだったとしても空欄となります。

◆length(文字列長表示)
文字列の長さを表示します。

{{ value|length }}

仮にvalueが['a', 'b', 'c', 'd']、または"abcd"の場合、表示内容は4となります。

また値が定義されていない場合は0を返します。

◆safe(エスケープ無効化)
Djangoでは、XSS対策として「<」「>」「'」「"」「&」の文字列が自動エスケープするデフォルト設定になっています。「safe」を使うことでエスケープを無効化できます。ちなみにエスケープとは上記の文字列を他の文字列に変換することです。(例えば「<」の場合「&lt;」)

{{ value|safe }}

例えばvalueの中身が<b>Django</b>だった場合、safeありなしで以下のように画面表示されます。。

safeなし→<b>Django</b>(<b></b>をただの記号として認識
safeありDjango(<b></b>により太字に変換と認識

なぜデフォルトでsafeなし(自動エスケープ)の設定になっているかというと、外部より<script></script>(Javascript)によってCookie等より重要情報を抜き取られる可能性があるためです。

したがって管理者以外のユーザーが入力するような箇所でなるべくsafeを使わないよう気をつけましょう。

◆date(日時フォーマット)
引数で指定したフォーマットで日時を表示します。

{{ user.last_login|"Y-m-d H:i" }}
#出力例 2021-4-18 10:30

引数をどのように設定するかについては、他にも色々あるので一度公式ドキュメントをご参照ください。

◆linenumbers(行番号付き)
行番号付きで表示
します。

{{ value|linenumbers }}

#出力例
1. one
2. two
3. three

◆urlize(リンク変換)
文字列内の URL と Email アドレスをクリック可能なリンクに変換します。

{{ value|urlize }}

例えば文字列内に
「https://note.com/saito_pythonista/m/m9b6026853e9a 参照ください。」とあり、urlizeによってリンク変換すると以下のようにクリック可能なリンクになります。※urlと文章の繋ぎの部分はスペース要です。

https://note.com/saito_pythonista/m/m9b6026853e9a 参照ください。」

◆upper/lower(大文字/小文字に変換)
upper/lowerを使うことで全て大文字/小文字に変換可能
です。

{{ value|upper }} #大文字に変換  Abc→ABC
{{ value|lower }} #小文字に変換  Abc→abc

timesince(経過時間の表示)
timesinceを使うことで経過(差分)時間を表示可能です。

{{ blog_date|timesince}} #現時刻との差分
{{ blog_date|timesince:comment_date }} #comment_dateとの差分

上記のようにtimesinceを使うことで、例えば「4 days, 6 hours前に投稿」というような表示が可能になります。

通常引数なしの場合は現時刻と変数の差分になり、引数を設定の場合は引数と変数の差分(comment_date - blog_date)になります。

timesinceに似たもフィルターでtimeuntilがあり、「後〇〇日で……」のような表現をすることができます。

4. テンプレートタグについて

テンプレートタグはロジックを制御(if etc...)したり、機能を拡張(extends etc...)することができます。

テンプレートタグは以下のように記述します。

{% タグ名 "引数" %}

djangoではかなりの数テンプレートタグが用意されているので、使用頻度の高い以下を解説していきます。

・if(条件分岐)
・for(ループ)
・extends(テンプレートの継承)
・include(外部テンプレートの読み込み)
・static(静的ファイルのurl取得)
・url(URLの逆引き)

◆if(条件分岐)
{% if %} タグを使うことで条件分岐が可能になります。

{% if athlete_list %}
   Number of athletes: {{ athlete_list|length }}
{% elif athlete_in_locker_room_list %}
   Athletes should be out of the locker room soon!
{% else %}
   No athletes.
{% endif %}

上記のようにほぼpython同様に使用しますが、{% endif %}によって最後閉じる必要があるので注意しましょう。

解説は割愛しますが、以下にいくつか使用例を紹介します。

and, or, notを使った条件分岐可能↓

{% if athlete_list and coach_list %}
   Both athletes and coaches are available.
{% endif %}

{% if not athlete_list %}
   There are no athletes.
{% endif %}

{% if athlete_list or coach_list %}
   There are some athletes or some coaches.
{% endif %}

==, !=, <, >, <=, >=, in, not in, is, and is notも使用可能↓

{% if somevar == "x" %}
 This appears if variable somevar equals the string "x"
{% endif %}

{% if "bc" in "abcdef" %}
 This appears since "bc" is a substring of "abcdef"
{% endif %}

フィルターを使用することも可能↓

{% if messages|length >= 100 %}
  You have lots of messages today!
{% endif %}

{% if %}タグはかなり頻出なのでぜひマスターしましょう。

◆for(ループ)
{% for %}、{% endfor %}とすることでループ処理をすることができます。

<ul>
{% for athlete in athlete_list %}
   <li>{{ athlete.name }}</li>
{% endfor %}
</ul>

  There are no athletes.

for タグのオプションとして 以下のように{% empty %} を使うことができます。これはループさせる配列が空、または存在しなかった場合に表示する文字列を指定できます。

{% for athlete in athlete_list %}
   <li>{{ athlete.name }}</li>
{% empty %}
   <li>Sorry, no athletes in this list.</li>
{% endfor %}

{% for %}タグも頻出なのでぜひマスターしましょう。

◆extends(テンプレートの継承)
{% extends %}タグは別のテンプレートを継承するために使用します。

{% extends "base.html" %}

基本的な使い方としては、base.htmlというベースのファイルを準備し、他ファイルではbase.htmlを継承し必要な部分のみ上書きしていきます

base.html

<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   ...
</head>
<body>
    #上書きする部分
    {% block header %}
    {% endblock %}
    
    #上書きする部分
    {% block main %}
    {% endblock %}
</body>
</html>

base.html準備し、他ファイルで継承する理由は、上記のようなhtmlフォーマットを何度も記述しないようにするためです。

他ファイルで上書きする部分に{% block ...%}タグを使用します。

継承先(〇〇.html)

{% extends "base.html" %} #base.htmlを継承

{% block header %}        #base.htmlのブロック部分を上書き
...
{% endblock %}

{% block main %}          #base.htmlのブロック部分を上書き
...
{% endblock %}

base.htmlを継承するため{% extends "base.html" %}で呼び出し、{% block ...%}内に記述していきます。

◆include(外部テンプレートの読み込み)
{% include %}タグ
他のテンプレートを読み込むためのタグです。ナビゲーションなどの部品化したテンプレートを読み込むような場合に使用します。

...
<div>
    {include "_navigation.html" }
</div>

◆static(静的ファイルのurl取得)
{% static %}タグ静的ファイルのURLを取得するタグです。

{% load static %}  #staticを使うためのおまじない

<link rel="stylesheet" href="{% static "css/style.css' %}">

<img src="{% static "images/no-image.png" %}" >

{% static "静的ファイルが存在するディレクトリ" %}でURLを取得します。

staticを使用する各テンプレートファイルで、{% load static %}を記載する必要があるので忘れないよう気をつけてください。

またstaticを使用するにあたっていくつかセッテイングが必要なので、詳細は以下をご確認ください。

◆url(URLの逆引き)
{% url %}タグ
urls.pyで設定したURLのパターン名からURLを逆引きするために使用します。

urls.pyを以下前提で解説します。

urls.py

from django.urls import path
from .views import listfunc, detailfunc

urlpatterns = [
   path('list/', listfunc, name='list'),
   path('detail/<int:pk>', detailfunc, name='detail'),
]

name='...'と設定した情報よりURLを逆引きします。
以下のように{% url %}タグを使用します。

    <a href="{% url 'list' %}">一覧ページ</a>
    <a href="{% url 'detail' value.pk %}">詳細ページ</a>

urls.pyのpathでpkやslugを設定しなければ{% url '...' %}とすればOKですが、pathでpkやslugの設定がある場合% url '...'  〇〇.pk(〇〇.slug) %}のように必要情報を与える必要があるのでご注意ください。

5. 最後に

いかがだったでしょうか。

DjnagoといえばMVTというくらいテンプレートの設定は必須です。

今回の記事ではテンプレートの設定方法から具体的な機能まで基礎的内容全て網羅しているかと思います。

テンプレートに関して何か詰まったときこの記事を辞書代わりに使っていただけると幸いです。













この記事が気に入ったらサポートをしてみませんか?