テンプレートでQuerySet型の値をjavascriptに渡したい
配列型や辞書型なら以下の通りで渡せるが、QuerySet型の場合はそのまま渡せない。
const sample = {{ object|safe }}
テンプレートタグを自作して対策した。
テンプレートタグの作り方
まずは独自のテンプレートタグの作り方
- アプリフォルダにtemplatetagsフォルダを作成
- templatetagsに
__init__.py
の空ファイルを作成 - templatetagsに
my_tags.py
のファイル(名前は自由)を作成し、ここに独自のテンプレートタグを作成してく。
app
├── views.py
├── ...
└── templatetags
├── __init__.py
└── my_tags.py
テンプレートタグの作り方
templatetags/my_tags.py
from django import template # 必須
register = template.Library() # 必須
@register.simple_tag # 必須
def double_number(number):
return number * 2
テンプレートでの使い方
sample.html
{% load my_tags %} {# ← 呼び出し #}
<p>2倍にする {{ double_number num }}</p> {# 「タグ名 引数」のように使用する #}
QuerySetを配列に変換
QuerySet型を配列に変換するテンプレートタグを作成していく。
templatetags/my_tags.py
from django import template
import json
from datetime import date, datetime, time
from decimal import Decimal
from django.utils.safestring import mark_safe
# date, datetime, time, decimalの変換関数
def json_serial(obj):
if isinstance(obj, (datetime, date, time)):
return obj.isoformat()
if isinstance(obj, Decimal):
return float(obj)
raise TypeError ("Type %s not serializable" % type(obj))
register = template.Library()
@register.simple_tag
def queryset_to_json(queryset):
ary = list(queryset.values()) # 1
json_ary = json.dumps(ary, ensure_ascii=False, default=json_serial) #2
return mark_safe(json_ary) #3
- list(queryset.values())
クエリセット内のオブジェクトを辞書の配列に変換 - json.dumps(ary, ensure_ascii=False, default=json_serial)
ここでjsonに変換する。しかしデータの中にオブジェクト(datetimeやdecimalなど)が含まれていると、エラーが発生するので、default=json_serial
で変換の定義を行っている。ここではdate, datetime, time, decimal
の変換を定義しているが、必要に応じて記述していく - mark_safe(json_ary)
HTMLエスケープを行わない
テンプレートでの使い方
sample.html
{% load my_tags %}
<script>
const sample = {% queryset_to_json object %};
</script>