"BOKU"のITな日常

62歳・文系システムエンジニアの”BOKU”は日々勉強を楽しんでます

djangoテンプレート内でforループで回す時の整理とデフォルト辞書利用時の注意など。

djangoテンプレートで{% for  xx in dic %} みたいにループを回して処理する時に、注意が必要なことがあるのでまとめておきます。

f:id:arakan_no_boku:20191230001930p:plain

 

forループの使い方について抜粋です

 

djangoテンプレート内でリスト・タプル・辞書型などの一括処理をする時にforループを使います。

リスト(List)、タプル(tuple)の場合の基本形は。

<table>
{% for v2 in lst2 %}
	<tr>
		<td>list</td>
		<td>{{ v2 }}</td>
	</tr>
{% empty %}
	<tr>
		<td>list</td>
		<td>中身が空です。</td>
	</tr>
{% endfor %}
</table>

です。

{% empty %}は、空の場合に何か処理したい場合に使います。

IF文をネストして空チェックとかしなくていいので、何気に便利です。

もちろん。

List、tupleが空の場合(例:lst2=[]で初期化したままの場合)に何か処理をする必要がなければ、{% empty %}は省略できます。

辞書の場合も同様です。

<table>
{% for k,v in dic3.items %}
	<tr>
		<td>辞書</td>
		<td>{{ k }}==>{{ v }}</td>
	</tr>
{% empty %}
	<tr>
		<td>辞書</td>
		<td>空です。</td>
	</tr>		
{% endfor %}
</table>

のように、辞書をループでまわすときは、itemsを使って、キーと値を取り出します。

辞書が空の時(例 dic3={}で初期化したまま)の場合に、特別に処理する必要があれば、{% empty %}のブロックが使えるのも同じです。

ループを逆順で処理したい場合は、いずれも「{% for t1 in tpl1 reversed %}」のように、「reversed」をつけることで実現できます。

また。

いずれもforループのブロック中で、以下の変数が使えます。

  • forloop.counter :現在のループカウンタ番号 ( 1 から順にカウント )
  • forloop.counter0 :現在のループカウンタ番号 ( 0 から順にカウント )
  • forloop.revcounter :現在のループカウンタ値 ( 1 から順に、末尾からカウント)
  • forloop.revcounter0 :在のループカウンタ値 ( 0 から順に、末尾からカウント)
  • forloop.first :最初のループであれば True
  • forloop.last :最後のループであれば True

これも何気に便利です。

例えば、以下のように使えます。

{% for v1 in lst1 %}
	{% if forloop.first %}
		<tr>
			<td>{{ forloop.counter0 }}</td>
			<td>最初のレコードです。</td>
		</tr>
	{% else %}
		{% if forloop.last %}
			<tr>
				<td>{{ forloop.counter0 }}</td>
				<td>最後のレコードです。</td>
			</tr>
		{% else %}
			<tr>
				<td>{{ forloop.counter0 }}</td>
				<td>{{ v1 }}</td>
			</tr>
		{% endif %}
	{% endif %}
{% endfor %}

とりあえず、こんなものです。

ここまでは、別に注意すべきことはありません。

 

注意しないといけないこと

 

今回の記事のポイントはここからです。

注意すべき点。

それは。

djangoのテンプレートでforループを回す時、組込みアルゴリズムであるデフォルト辞書(difaultdict)を直接渡せないという制約があることです。

デフォルト辞書については、こちらの記事でちょっと書いてます。

arakan-pgm-ai.hatenablog.com

理由はこちらに書いてあります。

docs.djangoproject.com

一部引用してまとめると。

テンプレート内では、この順番で実行しようとします:

  • 辞書検索
  • 属性やメソッドの検索
  • 数値のインデックス検索

その仕様の影響で「defaultdict」をそのまま渡すと「.items()」メソッドではなくデフォルト値を直接参照してしまうそうです。

なので。

例えば、views.pyの中で以下のようにカウンタにdefaultdictを使った場合。

dic4 = defaultdict(int)
dic4['C'] += 1
dic4['D'] += 1
dic4['A'] += 1
dic4['C'] += 1 

これをこのまま

'dic4': dic4

みたいにdjangoテンプレートに渡すとエラーになります。

回避策としては、 

'dic4': dict(dic4)

のように辞書型に明示的に変換してテンプレートに渡せばよいだけなのです。

わかってしまえば簡単な話なんですけどね。

自分の経験では、エラーメッセージから、その原因にたどりつくのに手間取りました。

正直。

ちょっとハマりました(笑)。

なので、備忘を兼ねて書いておこうかと思ったというわけです。

とりあえず、こんなところで。

ではでは。