DjangoのForm Widgetのテンプレートを変更する

2023/11/01に公開

概要

Djangoのforms.FormwidgetでテンプレートにレンダリングされるHTMLが決まってしまい、テンプレートで細かくカスタマイズすることができません。属性やクラスは付与できますが、forms.MultipleChoiceFieldで複数のチェックボックスを使う場合など囲ってるdivやlabelなどの細かいカスタマイズができないためCSSフレームワークを適応する時困ります。そんな時はそっくりテンプレートを入れ替えるのが吉なのかな?(すいません初Djangoなので手探り中)。テンプレートを変更する方法のメモです。

Djangoのバージョンは4.2です。

コード

クラス継承無し

from django import forms

class MyForm(forms.Form):
    choices = forms.MultipleChoiceField(
        choices = (
            ("1", "Foo"), 
            ("2", "Bar"), 
            ("3", "Baz"), 
            ("4", "Qux"), 
        ),
        widget  = forms.CheckboxSelectMultiple,
    )

    choices.widget.template_name = 'common/forms/widgets/checkbox_select.html'

クラス継承

from django import forms
 
class MyCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
    template_name = 'common/forms/widgets/checkbox_select.html'
    
class MyForm(forms.Form):
    choices = forms.MultipleChoiceField(
        choices = (
            ("1", "Foo"), 
            ("2", "Bar"), 
            ("3", "Baz"), 
            ("4", "Qux"), 
        ),
        widget  = MyCheckboxSelectMultiple,
    )

解説

widget.template_nameを上書いてやることで変更できます。ソースを見るとwidget.option_template_nameという変数もありますが、Djangoではテンプレートを使い回してるようで、各選択肢のテンプレはどれを使うか指定してるようです。今回は一ファイルにまとめるので無視しました。

使える変数は{%debug%}でも見れますが、django-debug-toolbarを使った方が見やすいでしょう。

元のテンプレートはこの辺で見つけることができます。

各Widgetのソースはこの辺にありますので、ここでどのテンプレを使ってるのか確認可能です。

ただ、一つだけ厄介な問題があって、ここで指定したテンプレを変更してもDjangoのrunserverのホットリロードが効かないんですよね。何か別のファイルを保存してやればリロードされますが面倒です。原因や改善方法がわかればまた共有します。

Discussion