django-bootstrap5を使って手軽にBootstrap5をDjangoのフォームに適用する

Bootstrapはフロントエンド向けのツールキットです。

getbootstrap.com

BootstrapにはCSSJavaScriptが用意されていて、ウェブページに組み込む場合は、HTMLタグにclass属性を指定すると、用意されているデザインが適用される、というものです。

メジャーバージョン間で互換性のない変更があり、Bootstrap4(バージョン 4.x)、Bootstrap5(バージョン 5.x)のようにメジャーバージョンの番号付きで呼ばれることがあります。

DjangoでBootstrapを使うには

BootstrapはHTMLタグにclass属性を指定できれば使えるので、DjangoでもテンプレートでCSSJavaScriptを読み込むように記述すれば使えます。

しかし、DjangoのForm機能を使う場合、inputタグなどのform内で利用するHTMLの文字列生成は、アプリ側のテンプレートではなくDjango内部で行われるので、出力されるタグにclass属性を付与するには少し工夫が必要です。

この記事では説明しませんが以下の方法などがあります。

  • widgetのテンプレートファイルを作成し、優先で使われるようにテンプレートローダーを設定する
  • Formクラスを使う際に、フィールドのwidgetにattrsでclass属性を指定する
    • 通化する場合はメタクラスで差し込む方法もある
    • テンプレートタグを作成し、Widgetのattrsを書き換える

いくつかある方法のうち、テンプレートタグを使ってDjangoのformの出力内容を変更するアプローチで実装されてるのが django-bootstrap5 です。

django-bootstrap5 24.2 documentation

django-bootstrap5を使うと手軽にBootstrapをDjangoに組み込めます。

インストール

Installation - django-bootstrap5 24.2 documentation

PyPIからインストールできます。

pip install django-bootstrap5

INSTALLED_APPSに django_bootstrap5 を追加します。

INSTALLED_APPS = [
    # ...
    'django_bootstrap5',
]

INSTALLED_APPSへの追加は、ライブラリ内に含まれるテンプレートファイルや、テンプレートタグを使用するために必要な作業です。

導入

Quickstart - django-bootstrap5 24.2 documentation

ドキュメントからリンクされていますが、exampleのアプリを参考にするとわかりやすかったです。

django-bootstrap5/example at main · zostera/django-bootstrap5 · GitHub

Bootstrapはmetaタグでviewportの指定や、CSSファイル、JavaScriptファイルの読込みが必要になります。

Bootstrap側のドキュメントの通りにlinkタグやscriptタグを直接記述もできますが、django-bootstrap5では、ベースのテンプレートファイルが用意されています。 このファイルを継承して使っておくと、Bootstrapに関する各種設定変更をDjangoのsettings.pyからできるようになるのでおすすめです。

https://github.com/zostera/django-bootstrap5/blob/main/src/django_bootstrap5/templates/django_bootstrap5/bootstrap5.html

アプリ作成

例として myapp を作ります。

python manage.py startapp myapp

FormとView作成

FormとViewは特にbootstrap5を意識せずに、Djangoのドキュメント通りに作成します。

myapp/forms.py:

from django import forms


FAVORITE_COLORS_CHOICES = {
    "blue": "Blue",
    "green": "Green",
    "black": "Black",
}


class MyForm(forms.Form):
    name = forms.CharField(label="名前")
    body = forms.CharField(label="本文", widget=forms.Textarea)
    favorite_colors = forms.MultipleChoiceField(
        required=False,
        widget=forms.CheckboxSelectMultiple,
        choices=FAVORITE_COLORS_CHOICES,
    )

myapp/views.py:

from django.views.generic import TemplateView
from . import forms


class IndexView(TemplateView):
    template_name = 'index.html'

    def get_context_data(self):
        return {'form': forms.MyForm()}

form という名前のコンテキストで index.htmlDjango Formのインスタンスを渡しています。

URL設定

サンプルとして作成したプロジェクトは myproject です。 myproject/urls.py にルートのURL設定があります。 作成したIndexViewを有効にしておきます。

myproject/urls.py:

from django.contrib import admin
from django.urls import path

from myapp import views as myapp_views

urlpatterns = [
    # ... (省略)
    path('', myapp_views.IndexView.as_view()),
]

テンプレート作成

この例では myapp/templates ディレクトリ以下にファイルを作っていますが、実際に使用する場合はextendsに指定するテンプレートパスなどとの整合性がとれていれば、ここではなくてもよいです。

myapp/templates/bootstrap.html:

{% extends 'django_bootstrap5/bootstrap5.html' %}

{% block bootstrap5_title %}{% block title %}{% endblock %}{% endblock %}

django-bootstrap5に含まれるテンプレートファイルを継承して、プロジェクト内で使用するbootstrap用のベーステンプレートを作ります。titleブロックを定義しているので、継承したファイルでは bootstrap5_title ブロックを使わずに、 title ブロックで title部分を記載できます。exampleと同様です。

myapp/templates/base.html:

{% extends 'bootstrap.html' %}

{% load django_bootstrap5 %}

{% block bootstrap5_content %}
    <div class="container">
        <h1>{% block title %}(no title){% endblock %}</h1>

        {% autoescape off %}{% bootstrap_messages %}{% endautoescape %}

        {% block content %}(no content){% endblock %}
    </div>

{% endblock %}

アプリ(プロジェクト)用のベーステンプレートです。各画面はこの base.html を継承して作成する想定です。exampleを参考に必要な部分だけを記載しています。

myapp/templates/index.html:

{% extends 'base.html' %}

{% load django_bootstrap5 %}

{% block title %}
Bootstrap5 フォーム
{% endblock %}

{% block content %}
<form method="post">
  {% csrf_token %}

  {% bootstrap_form form layout=layout size=size %}

  {% bootstrap_button button_type="submit" content="OK" %}
  {% bootstrap_button button_type="reset" content="Reset" %}
</form>
{% endblock %}

index.htmlでは django-bootstrap5 のテンプレートタグを使用しています。 bootstrap_formタグにformコンテキスト(IndexViewから渡されたMyFormのインスタンス)を渡して、class属性の付与などを行っています。

実行結果

ブラウザで http://127.0.0.1:8000/ にアクセスすると、Bootstrap5のデザインが適用されたフォームが表示されます。

サンプルコード全部

sample_nullpobug/django/django_bootstrap5 at main · tokibito/sample_nullpobug · GitHub