知識の枝

"All is well"

Djangoテンプレート 文字列でif分岐する方法

約387日前 2021年4月25日16:35
デジタル
Django

改訂履歴


2021/4/25 投稿

1. 背景


Djangoを使った開発中に覚えたことを備忘録として残します。

今回はDjangoのhtmlテンプレート内で文字列を使ったif分岐を行う方法を解説します。


2. ゴール


for文で取り出すモデルの内容(文字列)によって条件分岐し、それぞれ異なる装飾を行う。


3. はじめに


やりたいことのイメージ共有です。



ToDoアプリで各タスクに「優先度」を設定したとします。
上記の画像でいう「Urgent」「high」「Low」にあたります。


タスクを一覧表示したときに「優先度」も合わせて表示する場合、そのままforループでまわすと見た目が同じになってしまいます。
(同一の装飾が適用される)

できれば優先度が高いタスクは色を付けて目立つようにしたいですよね。


forループ内でif文を使って条件分岐させ、優先度の内容によって適用する装飾(CSS)を使い分けたい場合、一体どうやってやるのでしょうか?
その方法を解説したいと思います。


4. 文字列で条件分岐


models.pyで「Priority」という優先度のモデルを作成し、下記3種類の優先度パラメータを用意したとします。



Low ・・・ 低い
High ・・・ 高い
Urgent ・・・ 最優先

TaskモデルからPriorityモデルをForeignKeyで選択できるようにします。

models.py
class Priority(models.Model): #優先度のモデル
"""Priority list"""
priority = models.CharField(verbose_name='優先度', max_length=10, blank=True, null=True)

def __str__(self):
return self.priority


class Task(models.Model):
"""Task info"""
task = models.CharField(verbose_name='やること', max_length=255, blank=True, null=True)
priority = models.ForeignKey(
Priority, verbose_name='優先度', on_delete=models.PROTECT) #ここが優先度設定部

def __str__(self):
return self.task


このTaskモデルをListViewなどでhtmlテンプレートに呼び出したとします。
for文を使ってタスク一覧を表示してみましょう。

html
{% for task in task_list %}
<p>タスク内容:{{ task.task }}</p>
<p>優先度:{{ task.priority }}</p> #ここで優先度を表示する
{% endfor %}
この書き方では、「priority」の種類によらず全部同じ書き方になってしまいますね。

if文を使って条件分岐させてみましょう。
html
{% for task in task_list %}
<p>タスク内容:{{ task.task }}</p>
{% if task.priority == "Urgent" %}
<p style="color: red;">優先度:{{ task.priority }}</p> #Urgentの場合は赤色
{% elif task.priority == "High" %}
<p style="color: yellow;">優先度:{{ task.priority }}</p> #Highの場合は黄色
{% else %}
<p style="color: blue;">優先度:{{ task.priority }}</p> #Lowの場合は青色
{% endif %}
{% endfor %}
まず思いつく書き方はこんな感じですよね。でもこれだと文字が全部「青色(Low判定)」になってしまいます。

なぜでしょうか?
「Lowと判定した」というよりは、「どのif文にも引っ掛からなかった」と考えるのが妥当でしょう。

実はこれ 文字列として比較できていない んです。


念の為「task.priority」の型を確認してみます。
print(type(task.priority))
>>> <class 'app名.models.Priority'>
priorityには"Urgent"という文字列が入っているのでstr型かと思っていましたが、実はstr型ではなくモデル専用の型になっていました。


したがって、先ほどのif文で正しく比較するには次の3つの方法が考えられます。

①テンプレートに変数を渡したあと、テンプレート内でstr型に変換して比較する
②views.py内で予めstr型に変換しておき、テンプレートに渡す
③テンプレートにPriorityモデルを渡し、テンプレート内の比較で「=="Urgent"」とせずPriority型で比較する。


①の方法について詳しく解説します。
②と③はたぶん解決する方法だと思っていますが、試していないので動くか分かりません!


テンプレート内でstr型に変換するにはDjangoのビルトインフィルターの中の「stringformat」を利用します。

ビルトインフィルターについては こちら

引用すると

stringformat¶
Formats the variable according to the argument, a string formatting specifier. This specifier uses the printf-style String Formatting syntax, with the exception that the leading “%” is dropped.

For example:

{{ value|stringformat:"E" }}
If value is 10, the output will be 1.000000E+01.

https://docs.djangoproject.com/



「|stringformat: "s"」とすればstr型に変換できます。

したがって先ほどのif文を下記のように書き直しましょう。
html
{% for task in task_list %}
<p>タスク内容:{{ task.task }}</p>
{% if task.priority|stringformat:"s" == "Urgent" %}
<p style="color: red;">優先度:{{ task.priority }}</p> #Urgentの場合は赤色
{% elif task.priority|stringformat:"s" == "High" %}
<p style="color: yellow;">優先度:{{ task.priority }}</p> #Highの場合は黄色
{% else %}
<p style="color: blue;">優先度:{{ task.priority }}</p> #Lowの場合は青色
{% endif %}
{% endfor %}
これで当初の予定通りif文比較ができるようになります。


5. さいごに


今後も役に立ちそうな方法なので、ぜひ覚えましょう。
お疲れ様でした。