はじめに
Django の Form は (デフォルトの) テンプレートエンジン内で {{ form }}
のようにする1 と、全てのフィールドを HTML 出力してくれる。 これらの実体は Widget を用いることで変更できるのだが、Widget は単純に input や select タグとのマッチング用途で作られているため、例えば Label + (必須属性なら必須を示す *
をつける) + Inputフィールド、というような組み合わせを作りづらい。
また、1つのフォームで取り扱う項目が多い場合、これをグループに分け、グループ単位で一括で取り扱いたいということもある。
このように、Form の出力をカスタマイズする方法についてを考察する。
検証バージョン
- Python: 3.10.2
- Django: 4.0.5
Form 内 Field のグループ化
Form 内に引数0の関数を定義し、そこで自身のフィールドの一部を返すようにすることで実現できる。
例えば、以下のように定義すれば、テンプレート内で {% for field in form.group1 %}
のようにしてグループ化したフィールドを呼び出せる。
class MyForm(Form):
# 中略
def field_groups(self, keys: list) -> list:
return [self[k] for k in keys]
def group1(self):
return self.field_groups(['key1', 'key2'])
グループ化をまとめてレンダリングする
最初に示した "Label + (必須属性なら必須を示す *
をつける) + Inputフィールド、というような組み合わせを一括出力するような場合は、以下のように記述すれば良い。 レイアウト上必要な場合、適切な class を付与すること。
{% for field in fields %}
<div>
<label for="{{ field.id_for_label }}">
{{ field.help_text|default:field.label }}
{% if field.field.widget.is_required %}
<span class="required">*</span>
{% endif %}:
</label>
{{ field }}
</div>
{% endfor %}
これを別のファイル (fieldgroup.jinja) に切り出し、別のテンプレートで include して読み込むときは以下のようにすれば良い。
{% include '<中略>/fieldgroup.jinja' with fields=form.group1 %}
なお、記載していないが、fieldgroup.jinja
内に更に記載することで、エラー時の表記をフィールドに併せて行わせるといったことも可能になる。
補足
実際の Form を作成する場合は特定の要素を特別に扱いたい場合もあると思うが、それらは共通化せず、{{ form.field }}
(field は実際のフィールド名) のように直接扱う方が良いと思う。
あくまで共通化して処理できる部分を一括解決するために、グループ化と、グループに対して一括で処理する方法を示した。
-
context に
{'form': form}
として Form のインスタンスを渡している場合。 以後、これを前提とする。 ↩