Djangoで、表示・非表示切り替え可能なチェックボックスを作る

Python Django Djangoカスタムウィジェット

概要

Djangoで、表示・非表示切り替え可能なチェックボックスとなるカスタムウィジェットを作成していきます。

「タグリストを開く」というリンクを押すと、隠れていたチェックボックスが表示されます。 通常ページ

admin管理画面でも、同様に使うことができます。 管理画面

チェックボックスは項目数が多くなると幅を取りがちなので、こういった機能をつけたい機会もあるでしょう。今回はチェックボックスの例ですが、他にも応用が可能です。

ウィジェットを自作する

カスタムウィジェットとして作成しておくことで、通常ページだけでなくadmin管理画面でも簡単に利用することができ、保守や再利用の観点からも非常に捗ります。

まず、widgets.py というファイルをアプリケーション内に作っておきましょう。カスタムウィジェットは、こういったファイルに作ることが多いです。

中身は次のようにしておきます。

from django import forms


class AccordionCheckbox(forms.CheckboxSelectMultiple):
    template_name = 'app/widgets/accordion_check.html'

    class Media:
        css = {
            'all': [
                'app/css/accordion.css',

            ]
        }
        js = [
            'app/js/accordion.js'
        ]

forms.CheckboxSelectMultipleを基にしたウィジェットです。

このウィジェットを動かすために必要なcss・jsファイルをclass Media以下に書き、このウィジェットをHTMLとして描画するためのテンプレートをtemplate_nameで指定しておきます。

こういったウィジェット用のテンプレートも、widgetsのようなディレクトリに入れておくと分かりやすいです。app/widgets/accordion_check.htmlの中身は次のようにしておきます。

<div class="accordion-container">
    <a class="accordion-button">タグリストを開く</a>
    {% include "django/forms/widgets/multiple_input.html" %}
</div>

ほとんど既存のチェックボックスと同じです。表示・非表示を切り替えるa要素と、それらを囲むdiv要素があるだけです。

次に、accordion.cssを作成します。

div.accordion-container > ul {
    display: none;
}

div.open > ul {
    display: block;
}

a.accordion-button {
    color: #1967D2;
    cursor: pointer;
    font-size: 14px;
}

やっていることは、囲んでいるdiv要素にopenというクラスがついたら表示、そうでなければ非表示、というだけの指定です。

最後に、accordion.jsを作成します。

document.addEventListener('DOMContentLoaded', e => {
    for (const button of document.getElementsByClassName('accordion-button')) {
        button.addEventListener('click', e => {
            button.parentNode.classList.toggle('open');
        });
    }
});

これもシンプルで、「タグリストを開く」部分をクリックしたらdiv要素にopenというクラスをつけたり、消したりするだけです。

1点注意があります。Django、テンプレートの探索順序で詳しく説明していますが、プロジェクト直下にtemplatesディレクトリを置くような作り(settings.pyでDIRSに何か指定している)ならば、次のような設定をする必要があります。

INSTALLED_APPS = [
    'app.apps.AppConfig',  # マイアプリケーション
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.forms',  # 足す
]
...
...
FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'

自作ウィジェットを使ってみる

ウィジェットを作成したので、実際に使ってみましょう。

モデルフォームを利用している場合は、次のようにウィジェットを変更します。

class PostCreateForm(forms.ModelForm):

    class Meta:
        model = Post
        fields = '__all__'
        widgets = {
            'tags': AccordionCheckbox,
        }

通常のフォームならば、次のようになるでしょう。

class PostSearchForm(forms.Form):
    tags = forms.ModelMultipleChoiceField(widget=AccordionCheckbox, queryset=Tag.objects, required=False, label='検索タグ')

後は、このフォームをテンプレートに表示するだけです。{{ form.media }}が必要なので、それだけ忘れないようにしましょう。

    <form action="" method="POST">
        {{ form.as_p }}
        {% csrf_token %}
        <button type="submit">送信</button>
        {{ form.media }}
    </form>

admin管理画面で利用したい場合は、次のようにします。

from django.contrib import admin
from .forms import PostCreateForm
from .models import Post, Tag


class PostAdmin(admin.ModelAdmin):
    form = PostCreateForm


admin.site.register(Post, PostAdmin)

ModelAdminクラスを自作して、form属性に先ほどのフォームを設定するだけですね。

Relation Posts

Django、フォームの表示方法まとめ

Djangoで、フォームオブジェクトをテンプレートファイルに渡した際の、様々な表示方法についてです。{{ form.as_p }}や{% for field in form %} 、手作業での取り出し方法を説明していきます。

Python Django Bulma Bootstrap4

Djangoで、プレビュー付き画像アップロード欄を作る

DjangoでImageFieldを使うと画像のアップロード欄が作られますが、プレビューは表示されません。ウィジェットを自作し、プレビュー付きの画像アップロード欄を作ります。

Python Django Djangoカスタムウィジェット

Django、ファイルアップロード付きテキストエリアを作る

Djangoで、テキストウィジェットにファイルをドラッグアンドドロップすると、本文にファイルURLが挿入される処理を実装していきます。ブログ等のアプリケーションでは便利な機能です。

Python Django Djangoカスタムウィジェット

Comment

記事にコメントする

まだコメントはありません。