Djangoの入力フォームにBootstrapを適用するときのスマートな最適解


# あらすじ

Bootstrapを適用するのに「タグの指定がキレイになる方法」を探していてたどり着いた最終形です。

Djangoの公式チュートリアルを読みながら入力フォームを実装し、Bootstrapを適用してみました。
ところが、どうしても冗長で煩雑なコードになってしまうのです。
試行錯誤した結果、きれいに書く方法を見つけたのでご紹介します。

# なんか思ってたのと違った方法

「[Djangoのテンプレートに、Bootstrapのform-groupやform-controlを設定できないとき](http://strkita.hatenablog.com/entry/2017/08/17/232712)」
を参考にログインフォームでも試してみました。
これだとどうしても、`label`にBootstrapが適用されません。

# 上手くいった方法

`{{ form }}`だけで済む箇所の中にBootstrapのための`class`指定をしたくて、`{% for item in form %}`～`{% endfor %}`のように分解しています。ここまでは上記の思ってたのと違った方法と同じです。

重要なのは、`for item in form`の`item`には、 **「充分過ぎるくらい情報が詰まっている」** ということです。
DjangoAdminのページ内で設定できる項目はすべて網羅しています。
データのIDと表示名、データ型まで、すべてです。
これをインテリセンスを駆使して、チェーンでプロパティを指定する。

それを各所に散りばめてあげましょう。そうすると、DjangoのAdminページ内で編集した後に、コードを変えずに、キレイに画面に反映されます。
Adminページで項目を増減しても、必須項目のチェックをオンオフしても、いちいちコードを書き換える必要はありません。
なんてスマートな記述なのでしょう。

といったものの、Django利用者としては、まだまだ素人です。
もっといいやり方があればコメント欄などで教えていただけると嬉しいです。

``` django
{% comment %} 以上略 {% endcomment %}
<form method="post" action="{% url 'login' %}" class="form-group">
    {% csrf_token %}
    {% for item in form %}
        <div class="form-group">
            <label for="{{item.id_for_label}}">{{item.label}}</label>
            <input
                type="{{item.field.widget.input_type}}"
                class="form-control"
                {% if item.field.required %}required{% endif %}
                name="{{item.name}}"
                id="{{item.id_for_label}}">
        </div>
    {% endfor %}
    <button type="submit" class="submit btn btn-primary">Login</button>
    <input type="hidden" name="next" value="{{ next }}"/>
</form>
{% comment %} 以下略 {% endcomment %}
```

# 表示結果

![Inked127.0.0.1_8000_accounts_login_(iPhone 6_7_8) (1)_LI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134703/3bdabb45-ac67-fb4d-6dd7-af8a7824d6e6.png)

# 工夫したところ

- `required`を付ける付けないのところ
- labelタグの関連づけに`name`ではなく、`id_for_label`を使ったところ
- input type にも動的指定ができた
- 結果としてすべて動的な記述ができたこと
- マジックナンバー的なハードコーディングがなくなった

どちらもリファレンス~~のフォントが汚くて読みたくない~~から見つけるのが難しく、
Vscodeのデバッガでオブジェクトの中身を調べました。その結果見つけたプロパティから文字列を取り出して利用するようにしました。

~~ブラウザのフォント設定を変更すれば済む話だということに気づいたのは、この記事を書いている今です。~~
~~とはいえUXの観点からみればフォントの設定を自力で変更するのは、ユーザーにとっての負担になるので、早急に変更すべきと思いますね。~~

本来はライブラリの公式ドキュメントをよく読んで実装するべきですが、
今回は逆で、デバッガで機能を発見し、機能毎のリファレンスを読みに行くという流れにしました。

# Bootstrapの適用方法

## BootstrapのCDNを組み込む

ここを参考にして秒で終わらせました。
１行書くだけだし、早いのでオススメです。

[Starter-Template | Bootstrap](https://getbootstrap.com/docs/4.3/getting-started/introduction/#starter-template)

## 他の方法

django-extentionを使用すると他にも方法があるみたいです。
出来るだけシンプルな構成を保ちたい人は避け、
複雑な構成でも完全にコントロールできる人はチャレンジすると良さそうです。

- [Django フォームにて CSS クラスを設定する方法](https://python.keicode.com/django/form-add-class.php)
- [Python Django入門 (4)](https://qiita.com/kaki_k/items/6e17597804437ef170ae)
- [Djangoのフォームデザインを簡単かつ自由にカスタマイズする方法](https://hodalog.com/how-to-use-bootstrap-4-forms-with-django/)
- [django-bootstrap4 | ライブラリ](https://django-bootstrap4.readthedocs.io/en/latest/)
- [DjangoでBootstrap4を使う方法](https://qiita.com/S2notC2/items/82808558383a773da942)

# ログインページ本体

個人的に機能の実装をするときに以下が一番わかりやすかったです。参考になりました。
[Django2 でユーザー認証（ログイン認証）を実装するチュートリアル -2- サインアップとログイン・ログアウト](https://it-engineer-lab.com/archives/544)

# 環境

Django 2.2
python 3.8
たぶん最新の環境なら通用します。

**Excelsior!**