11
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

はじめに

DjangoでWebアプリ開発をしている中で、1つの問題に直面しました。Djangoのテンプレートを素直に使用するだけでは、アコーディオンメニューを作れないという問題です。複数のチェックボックスを選択するフォームを作っている際に、選択肢が数百個に及ぶ可能性があり、見出しごとに選択肢を分割するアコーディオンメニューにしたいと考えました。この記事はその実現方法の備忘録です。

作戦

基本的な複数選択のチェックボックスを作るには、Djangoに用意されているCheckboxSelectMultipleというWidgetを利用します。このCheckboxSelectMultipleをオーバーライドすることで、アコーディオンメニューを実現することを目指しました。

分析

まずはDjango本体のソースコードを見ていきましょう。

上記のリポジトリを追っていくと、CheckboxSelectMultipleは次のようにクラスが継承されていることが分かります。

class CheckboxSelectMultiple(RadioSelect):
    hogehoge

class RadioSelect(ChoiceWidget):
    input_type = "radio"
    template_name = "django/forms/widgets/radio.html"
    option_template_name = "django/forms/widgets/radio_option.html"
    use_fieldset = True

そして、ソースコードを読み解いていくと、option_template_nameが選択肢のチェックボックスひとつひとつのテンプレートであり、template_nameが選択肢全体のテンプレートであることが分かります。今回は複数のチェックボックスというロジックはそのままにアコーディオンメニューを作ろうとしているので、このtemplate_nameの部分をオーバーライドして変更すれば良いでしょう。

実装

分析をもとに次のような実装をしました。

まずは、新しいClassを作ります。今回オーバーライドするのはtemplate_nameだけであるため、CheckboxSelectMultipleを継承して、template_nameのみ記載します。

class CheckboxSelectMultipleWithHeading(CheckboxSelectMultiple):
    template_name = "<テンプレートのパス>"

そして、使用するテンプレートを自分で作成します。今回はBootStrapを使用して、デフォルトで使用されているテンプレートを改変し、アコーディオンメニューにしました。

{% with id=widget.attrs.id %}
<div{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>
    <div class="accordion" id="accordionExample">
    {% for group, options, index in widget.optgroups %}
        <div class="accordion-item">
            <h2 class="accordion-header" id="headingOne">
                <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapse_{{ index }}" aria-expanded="true" aria-controls="collapseOne">
                    {{group}}
                </button>
            </h2>
            <div id="collapse_{{ index }}" class="accordion-collapse collapse show p-2" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
                {% for option in options %}
                    <div>{% include option.template_name with widget=option %}</div>
                {% endfor %}
            </div>
        </div>
    {% endfor %}
    </div>
</div>
{% endwith %}

これにより下図のようなフォームを作ることができました。

スクリーンショット 2023-07-04 11.38.34.png

11
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?