Djangoのフォームデザインを簡単かつ自由にカスタマイズする方法

Djangoにはフォーム関連のフレームワークが強力でバリデーションをいい感じに行ってくれるのですが、デザイン面の調整が難しくて苦戦中です。

例えばCSSのクラスを付与したい時、次のようにバックエンド側に処理を書く必要があります。

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class SignUpForm(UserCreationForm):
    username = forms.CharField(
        max_length=100,
        widget=forms.TextInput(attrs={'class': "form-control"}),
    )
    password = forms.CharField(widget=forms.PasswordInput)

直感的ではないので、この書き方はあまり好きではありません。デザインに関わるコードは可能な限りテンプレート側に直接記述したいですよね。

Bootstrap4やFoundationなどのCSSフレームワーク対応のライブラリなどいくつか試した結果、 django-widget-tweaks というのが最も自由度が高く、HTMLライクに記述できて分かりやすかったため、情報をまとめます。

前準備

ライブラリのインストール

まず django-widdget-tweaks をインストールします。ライブラリの情報は PyPI でチェックできます。

pip install django-widget-tweaks

settings.pyの編集

widget_tweaksINSTALLED_APPS に追記します。

INSTALLED_APPS = [
    .....
    'widget_tweaks',
]

widget_tweaksのロード

フォームを出力したいテンプレートで widget_tweaks をロードします。

{%!l(MISSING)oad widget_tweaks %!}(MISSING)

実装

widget_tweaksは2種類の方法を使ってフォームのデザインを調整します。

  1. 「add_class」テンプレートフィルター
  2. 「render_field」テンプレートタグ

今回は add_class を使い、下図のようなシンプルだけどいい感じに整っているフォームを作ってみます。

Bootstrap4で綺麗に整えたdjangoのフォーム

forms.pyの編集

特にCSS関連の情報を記述する必要はなく、スッキリかけます。

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class SignUpForm(UserCreationForm):
    password = forms.CharField(widget=forms.PasswordInput)
    class Meta:
        model = User
        fields = ('username', 'email', 'password')

テンプレートの編集

HTMLライクにストレスなくコーディングできます。

{{ form.hogehoge|add_class:'form-control' }} の部分がライブラリのルールに沿ったコードです。

<form action="{%!u(MISSING)rl 'sign_up' %!}(MISSING)" method="post">
  {%!c(MISSING)srf_token %!}(MISSING)

  <div class="form-group row">
    <label for="{{ form.username.id_for_label }}" class="col-sm-3 col-form-label">ユーザー名</label>
    <div class="col-sm-9">
      {{ form.username|add_class:'form-control' }}
      {%!f(MISSING)or error in form.username.errors %!}(MISSING)
        <span class="help-block">{{ error }}</span>
      {%!e(MISSING)ndfor %!}(MISSING)
    </div>
  </div>
  <div class="form-group row">
    <label for="{{ form.email.id_for_label }}" class="col-sm-3 col-form-label">メールアドレス</label>
    <div class="col-sm-9">
      {{ form.email|add_class:'form-control' }}
      {%!f(MISSING)or error in form.email.errors %!}(MISSING)
        <span class="help-block">{{ error }}</span>
      {%!e(MISSING)ndfor %!}(MISSING)
    </div>
  </div>
  <div class="form-group row">
    <label for="{{ form.password1.id_for_label }}" class="col-sm-3 col-form-label">パスワード</label>
    <div class="col-sm-9">
      {{ form.password1|add_class:'form-control' }}
      {%!f(MISSING)or error in form.password.errors %!}(MISSING)
        <span class="help-block">{{ error }}</span>
      {%!e(MISSING)ndfor %!}(MISSING)
    </div>
  </div>
  <hr>
  <div class="form-group row">
    <div class="col-sm">
      <button type="submit" class="btn btn-info btn-block">登録</button>
    </div>
  </div>
</form>

まとめ

Djangoのフォームを自由にカスタマイズできるようになりました。やったね!