最終投稿日:2022年6月18日
Django(テンプレート)
基本
● コメント
{# ほげほげ~ #}
● 変数
{{変数名}}
例)
例)
以下の様に views.py からアサインされた場合
d = {'hoge':'ほげ', 'foo':['あいう','かきく','さしす'], 'bar':{'hoge':'ほげ','foo':'ふ~','bar':'ばぁ'}} {{hoge}} {!!str_repeat(" ", 4)!!} ほげ #文字列としてリストを表示する
{{foo}} {!!str_repeat(" ", 4)!!} ['あいう', 'かきく', 'さしす']
#各要素が取得できる
{% for s in foo %}
{{s}}
{% endfor %} #文字列として辞書を表示する
{{bar}} {!!str_repeat(" ", 4)!!} {'hoge': 'ほげ', 'foo': 'ふ~', 'bar': 'ばぁ'}
#各要素が取得できる
{{bar.hoge}} {!!str_repeat(" ", 4)!!} ほげ
【注意】
辞書型の場合要素名を変数にすると値を取得できません!
{% for key in bar %}
#これは取得できない
{{bar.key}}
{% endfor %}
※この場合は、以下で説明する load を使いフィルタを自作する
d = {'hoge':'ほげ', 'foo':['あいう','かきく','さしす'], 'bar':{'hoge':'ほげ','foo':'ふ~','bar':'ばぁ'}} {{hoge}} {!!str_repeat(" ", 4)!!} ほげ #文字列としてリストを表示する
{{foo}} {!!str_repeat(" ", 4)!!} ['あいう', 'かきく', 'さしす']
#各要素が取得できる
{% for s in foo %}
{{s}}
{% endfor %} #文字列として辞書を表示する
{{bar}} {!!str_repeat(" ", 4)!!} {'hoge': 'ほげ', 'foo': 'ふ~', 'bar': 'ばぁ'}
#各要素が取得できる
{{bar.hoge}} {!!str_repeat(" ", 4)!!} ほげ
【注意】
辞書型の場合要素名を変数にすると値を取得できません!
{% for key in bar %}
#これは取得できない
{{bar.key}}
{% endfor %}
※この場合は、以下で説明する load を使いフィルタを自作する
● load
自作したフィルタ等を読み込む
【制約】
{% load hoge %} {!!str_repeat(" ", 4)!!} ※hoge.py を読み込んでいる
※setting.py の INSTALLED_APPS にアプリの登録を忘れない事!
各アプリに作成する(ライブラリ的なファイルを蓄積する専用のアプリを作っておくと良いかも。)
ディレクトリ名は【templatetags】となる
[アプリ]
|
+--- [templatetags]
|
+--- [__init__.py]
+--- [hoge.py]
例)hoge.py
ディレクトリ名は【templatetags】となる
[アプリ]
|
+--- [templatetags]
|
+--- [__init__.py]
+--- [hoge.py]
辞書型の変数に対して、要素名を変数で指定できる
from django import template
register = template.Library() #メソッド名と同じにするのはお約束か
@register.filter(name='lookup')
def lookup(value, arg, default=""):
if arg in value:
return value[arg]
else:
return default 【説明】
value には、辞書型の変数が入り、arg に要素めいの変数が入ります。
テンプレート側からの記述は {{hoge|lookup:i}} って感じ。
value の中に arg 要素が存在すれば、その値(value[arg])を返却するだけです。 【注意】
フィルタは引数を1つしか渡せません。
なので説明の引数 default は、テンプレート側から指定できるものではありません。
フィルタの定義が完成したらテンプレートから以下の様に読み込むregister = template.Library() #メソッド名と同じにするのはお約束か
@register.filter(name='lookup')
def lookup(value, arg, default=""):
if arg in value:
return value[arg]
else:
return default 【説明】
value には、辞書型の変数が入り、arg に要素めいの変数が入ります。
テンプレート側からの記述は {{hoge|lookup:i}} って感じ。
value の中に arg 要素が存在すれば、その値(value[arg])を返却するだけです。 【注意】
フィルタは引数を1つしか渡せません。
なので説明の引数 default は、テンプレート側から指定できるものではありません。
{% load hoge %} {!!str_repeat(" ", 4)!!} ※hoge.py を読み込んでいる
※setting.py の INSTALLED_APPS にアプリの登録を忘れない事!
【小技】
ラジオボタン等は、普通に設定すると「・」や改行されてしまう。
これを1行で表示されたい場合は、カスタムフィルタでも難しいですが、スタイルシートを使うと簡単です。
li{list-style:none;display:inline-block;} ※フィルタを自作する場合は、以下の様に頑張る。。(UL タグと LI タグを削除する)
@register.filter(name='hoge')
def hoge(value):
#受け取った値を文字列にキャストする
tmp = str(value)
#改行を全て削除し、1行のコードにする
tmp = tmp.replace('\n','')
#タグからタグまでの正規表現で、必要なコードを検索する
m = re.search(r'<label.+/label>', tmp)
#必要なコードを抜き出す
tmp = tmp[ m.span()[0] : m.span()[1] ]
#その中で不要なタグがあれば削除する
tmp = tmp.replace('</li>','')
#不要なタグ分繰り返す
tmp = tmp.replace('<li>','')
return tmp
これを1行で表示されたい場合は、カスタムフィルタでも難しいですが、スタイルシートを使うと簡単です。
li{list-style:none;display:inline-block;} ※フィルタを自作する場合は、以下の様に頑張る。。(UL タグと LI タグを削除する)
@register.filter(name='hoge')
def hoge(value):
#受け取った値を文字列にキャストする
tmp = str(value)
#改行を全て削除し、1行のコードにする
tmp = tmp.replace('\n','')
#タグからタグまでの正規表現で、必要なコードを検索する
m = re.search(r'<label.+/label>', tmp)
#必要なコードを抜き出す
tmp = tmp[ m.span()[0] : m.span()[1] ]
#その中で不要なタグがあれば削除する
tmp = tmp.replace('</li>','')
#不要なタグ分繰り返す
tmp = tmp.replace('<li>','')
return tmp
テンプレートの共通化
ページが複数ある場合は、全体のHTML構造やヘッダーやフッター等共通する部分があります。
その場合はテンプレートを「親」「子」に分け、継承関係を作ると良い。
例)
その場合はテンプレートを「親」「子」に分け、継承関係を作ると良い。
例)
[templates/layout/base.html]
#templates は、settings.py で設定したディレクトリ
<html>
<head>
#コントローラからアサインされた変数を使用する事が可能
<title>{{my_title}}</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
#インクルードもできる
{% include 'layout/header.html' %}
#my_body が、ブロック名となる
{% block my_body %}{% endblock %}
</body>
</html> [templates/アプリ名/index.html]
#base.html を継承する
{% extends 'layout/base.html' %}
#モジュール等の読み込みは継承元ではダメっぽい。これは適当なモジュールです!
{% load humanize %}
#ブロック名に対応する部分に流し込む
{% block my_body %}
基本!
{{200000|intcomma}}
{% endblock %} [templates/layout/header.html]
へっだ~<BR>
【テクニック】
#templates は、settings.py で設定したディレクトリ
<html>
<head>
#コントローラからアサインされた変数を使用する事が可能
<title>{{my_title}}</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
#インクルードもできる
{% include 'layout/header.html' %}
#my_body が、ブロック名となる
{% block my_body %}{% endblock %}
</body>
</html> [templates/アプリ名/index.html]
#base.html を継承する
{% extends 'layout/base.html' %}
#モジュール等の読み込みは継承元ではダメっぽい。これは適当なモジュールです!
{% load humanize %}
#ブロック名に対応する部分に流し込む
{% block my_body %}
基本!
{{200000|intcomma}}
{% endblock %} [templates/layout/header.html]
へっだ~<BR>
決まったヘッダーを出力する場合は、上記の様な記述で問題ありませんが、テンプレートによってことなるヘッダーを出力したい場合は、
継承元でインクルードするヘッダーをブロックで囲み、継承先でオーバーライドする方法があります。
例)
継承元でインクルードするヘッダーをブロックで囲み、継承先でオーバーライドする方法があります。
例)
【継承元】
{% load static %}
<html>
<head>
<title></title>
</head>
<body>
#通常は layout/header.html をヘッダーとして出力
{% block my_header %}{% include 'layout/header.html' %}{% endblock %}
{% block my_body %}{% endblock %}
</body>
</HTML> 【継承先】
{% extends 'layout/base.html' %}
#my_header をオーバーライドして layout/header2.html に変更できる
{% block my_header %}{% include 'layout/header2.html' %}{% endblock %}
{% block my_body %}
ボディ
{% endblock %}
{% load static %}
<html>
<head>
<title></title>
</head>
<body>
#通常は layout/header.html をヘッダーとして出力
{% block my_header %}{% include 'layout/header.html' %}{% endblock %}
{% block my_body %}{% endblock %}
</body>
</HTML> 【継承先】
{% extends 'layout/base.html' %}
#my_header をオーバーライドして layout/header2.html に変更できる
{% block my_header %}{% include 'layout/header2.html' %}{% endblock %}
{% block my_body %}
ボディ
{% endblock %}
URLの生成
● 書式
{% url 'ネームスペース名 : ページ名' %}
ネームスペース名は、プロジェクトの urls.py で指定した namespace 名となります。
ページ名は、各アプリの urls.py で指定した name 名となります。
例)
[hello/urls.py]
url(r'^index/$', IndexView1.as_view(), name='index1')
url(r'^index/(?P<id>\d+)/(?P<foo>\w+)$', IndexView2.as_view(), name='index2')
url(r'^index/(\d+)/(\w+)$', IndexView2.as_view(), name='index3')
上記の場合はリンクはそれぞれ以下の様になります。
<a href="{% url 'hello:index1' %}">リンク1
<a href="{% url 'hello:index2' id=111 foo='ccc' %}">リンク2
#パラメータは空白区切りで記述できる
<a href="{% url 'hello:index3' 111 'ccc' %}">リンク2 {% static 'パス' %}
static ディレクトリ配下の img 等を参照する場合の書式。 ※static をロードする必要があるので注意!
例)
#static の設定をロードする
{% load static %}
#階層も普通に記述できる
<link rel='stylesheet' href='{% static "hoge/base_css.css" %}' >
ネームスペース名は、プロジェクトの urls.py で指定した namespace 名となります。
ページ名は、各アプリの urls.py で指定した name 名となります。
例)
[hello/urls.py]
url(r'^index/$', IndexView1.as_view(), name='index1')
url(r'^index/(?P<id>\d+)/(?P<foo>\w+)$', IndexView2.as_view(), name='index2')
url(r'^index/(\d+)/(\w+)$', IndexView2.as_view(), name='index3')
上記の場合はリンクはそれぞれ以下の様になります。
<a href="{% url 'hello:index1' %}">リンク1
<a href="{% url 'hello:index2' id=111 foo='ccc' %}">リンク2
#パラメータは空白区切りで記述できる
<a href="{% url 'hello:index3' 111 'ccc' %}">リンク2 {% static 'パス' %}
static ディレクトリ配下の img 等を参照する場合の書式。 ※static をロードする必要があるので注意!
例)
#static の設定をロードする
{% load static %}
#階層も普通に記述できる
<link rel='stylesheet' href='{% static "hoge/base_css.css" %}' >
制御系
● if文
{% if foo == 1 %}
<div>ほげ</div>
{% elif foo == 2 %}
<div>ふ~</div>
{% else %}
<div>ばぁ</div>
{% endif %}
<div>ほげ</div>
{% elif foo == 2 %}
<div>ふ~</div>
{% else %}
<div>ばぁ</div>
{% endif %}
● for文
コントローラ側より以下の様なリストがアサインされた場合
{'arr_hoge':['hoge','foo','bar','fuga']}
例)
{% for i in arr_hoge %}
{{i}}
{{forloop.counter0}} ※0からの index を取得できる
{{forloop.counter}} ※1からの index を取得できる
{% endfor %}
{'arr_hoge':['hoge','foo','bar','fuga']}
例)
{% for i in arr_hoge %}
{{i}}
{{forloop.counter0}} ※0からの index を取得できる
{{forloop.counter}} ※1からの index を取得できる
{% endfor %}
● with文
テンプレートの中で何度も使う変数をキャッシュするらしい。
例)
{% for i in bar %}
{{bar|lookup:i}}
{% with bar|lookup:i as v %} ※フィルターを使った変数も大丈夫!
{{v}} ※変数 v が値をキャッシュする
{% endwith %}
{% endfor %} ※ここまでの範囲しかキャッシュしない
例が悪いが、ループ中 {{bar|lookup:i}} と {{v}} の値は同じになる
例)
{% for i in bar %}
{{bar|lookup:i}}
{% with bar|lookup:i as v %} ※フィルターを使った変数も大丈夫!
{{v}} ※変数 v が値をキャッシュする
{% endwith %}
{% endfor %} ※ここまでの範囲しかキャッシュしない
例が悪いが、ループ中 {{bar|lookup:i}} と {{v}} の値は同じになる
form 制御
form クラスの内容を制御します
● お手軽
<form method='POST'>
{{form}} ※form の名前でアサインされている場合
{% csrf_token %} ※トークンを発行する
<input type='submit' value='登録'>
</form> 【メモ】
{{form}} が一番お手軽だが、各フィールドを改行してくれないので見た目が酷い。
{{form.as_p}} とすると各フィールドを改行してくれるので、見た目は良くなる!
{{form}} ※form の名前でアサインされている場合
{% csrf_token %} ※トークンを発行する
<input type='submit' value='登録'>
</form> 【メモ】
{{form}} が一番お手軽だが、各フィールドを改行してくれないので見た目が酷い。
{{form.as_p}} とすると各フィールドを改行してくれるので、見た目は良くなる!
● for 文で全フィールドを回して制御する
{% for field in form.visible_fields %}
{% if field.errors.as_text != '' %} ※エラーがあった場合
{{field.errors.as_text|cut:'* '}}<br> ※勝手に[* ]が付与されちゃうので、フィルタでカットしている
{% endif %}
{{ field.label_tag }} {{ field }}
<br>
{% endfor %} 【メモ】
表示属性の部品と hidden 属性の部品それぞれにイテレータがあります
表示 部品:form.visible_fields
hidden 部品:form.hidden_fields
{% if field.errors.as_text != '' %} ※エラーがあった場合
{{field.errors.as_text|cut:'* '}}<br> ※勝手に[* ]が付与されちゃうので、フィルタでカットしている
{% endif %}
{{ field.label_tag }} {{ field }}
<br>
{% endfor %} 【メモ】
表示属性の部品と hidden 属性の部品それぞれにイテレータがあります
表示 部品:form.visible_fields
hidden 部品:form.hidden_fields
● 個々のフィールドを制御する
{% if form.myname.errors.as_text != '' %}
{{form.myname.errors.as_text|cut:'* '}}<br>
{% endif %}
{{form.myname.label}} {{form.myname}}
<br>
{{form.mysex.label}}
{{form.mysex.0}} ※ラジオボックスやチェックボックスオブジェクトはイテレータなので index で個々に制御できる
{{form.mysex.1}}
{{form.mysex.2}}
<br>
{% for field in form.chk %} ※イテレータなので当然 for 文で回せる(chk はチェックボックスオブジェクトとする)
{{field}}
{% endfor %}
<br>
{{form.syumi.as_hidden}} ※hidden 属性にできる
<br>
{% for field in form.visible_fields %} ※ループで回すと楽
{{ field.as_hidden }}
{% endfor %}
<br>
{{form.mail.value}} ※値のみを取得する
{{form.myname.errors.as_text|cut:'* '}}<br>
{% endif %}
{{form.myname.label}} {{form.myname}}
<br>
{{form.mysex.label}}
{{form.mysex.0}} ※ラジオボックスやチェックボックスオブジェクトはイテレータなので index で個々に制御できる
{{form.mysex.1}}
{{form.mysex.2}}
<br>
{% for field in form.chk %} ※イテレータなので当然 for 文で回せる(chk はチェックボックスオブジェクトとする)
{{field}}
{% endfor %}
<br>
{{form.syumi.as_hidden}} ※hidden 属性にできる
<br>
{% for field in form.visible_fields %} ※ループで回すと楽
{{ field.as_hidden }}
{% endfor %}
<br>
{{form.mail.value}} ※値のみを取得する




