【超便利】Djangoフォームでラジオボタンをレンダリング:`forms.RadioSelect`でスマートなフォーム設計


forms.RadioSelectは、Djangoフォームにおいてラジオボタンの表示をカスタマイズするためのウィジェットです。モデルフィールドの選択肢をラジオボタンとしてレンダリングし、ユーザーが選択できるようにします。標準のSelectウィジェットとは異なり、forms.RadioSelectは各選択肢を個別のラジオボタンで表示します。

使用方法

forms.RadioSelectを使用するには、以下の手順に従います。

  1. フォームクラスを定義する
    • フォームクラスを定義し、ラジオボタンで表示したいフィールドをModelChoiceFieldまたはChoiceFieldとして宣言します。
  2. widget引数を指定する
    • ModelChoiceFieldまたはChoiceFieldwidget引数にforms.RadioSelectを指定します。
  3. 選択肢を定義する
    • ModelChoiceFieldの場合は、モデルのchoices属性で選択肢を定義します。
    • ChoiceFieldの場合は、フィールドのコンストラクタで選択肢をタプルとして渡します。
  4. テンプレートでレンダリングする
    • テンプレートで{{ form.field_name }}を使用してフォームフィールドをレンダリングすると、ラジオボタンが表示されます。

from django import forms
from .models import MyModel

class MyForm(forms.ModelForm):
    status = forms.ModelChoiceField(
        queryset=MyModel.objects.all(),
        widget=forms.RadioSelect,
        label="ステータス"
    )

class MyOtherForm(forms.Form):
    payment_method = forms.ChoiceField(
        choices=(
            ('credit_card', 'クレジットカード'),
            ('paypal', 'PayPal'),
        ),
        widget=forms.RadioSelect,
        label="支払い方法"
    )

上記の例では、MyFormクラスはMyModelモデルのstatusフィールドをラジオボタンで表示し、MyOtherFormクラスはpayment_methodフィールドをカスタムの選択肢でラジオボタンとして表示します。

オプション

forms.RadioSelectには、以下のオプションを指定できます。

  • prefix: ラジオボタングループのIDプレフィックスを指定
  • empty_label: 空の選択肢のラベルを指定
  • choices: 選択肢をタプルとして指定する場合に使用
  • attrs: ラジオボタンのHTML属性を指定するための辞書
  • ラジオボタンのバリデーションは、Djangoの標準的なバリデーションロジックによって行われます。
  • forms.RadioSelectは、BootstrapなどのCSSフレームワークと組み合わせて使用することで、よりスタイリッシュなラジオボタンを作成できます。


モデルとフォームの定義

from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=255)
    body = models.TextField()
    status = models.CharField(
        max_length=20,
        choices=(
            ('draft', '下書き'),
            ('published', '公開済み'),
        ),
        default='draft'
    )

class ArticleForm(forms.ModelForm):
    status = forms.ModelChoiceField(
        queryset=Article.objects.all(),
        widget=forms.RadioSelect,
        label="公開ステータス",
    )

    class Meta:
        model = Article
        fields = ['title', 'body', 'status']

このコードでは、Articleモデルはtitlebodystatusという3つのフィールドを持っています。statusフィールドは、記事が下書きか公開済みかを表す文字列フィールドです。

ArticleFormフォームクラスは、Articleモデルに基づいており、titlebodystatusフィールドのすべてを編集できるようにします。statusフィールドには、forms.RadioSelectウィジェットが使用されており、記事の公開ステータスを選択するためのラジオボタンが表示されます。

テンプレートでのレンダリング

以下のテンプレートは、ArticleFormフォームをレンダリングします。

{% extends 'base.html' %}

{% block content %}
<h1>記事作成</h1>

<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">作成</button>
</form>
{% endblock %}

このテンプレートは、base.htmlをベースとしており、contentブロック内でArticleFormフォームをレンダリングします。{{ form.as_p }}タグは、フォームのすべてのフィールドをpタグで囲まれたHTMLとしてレンダリングします。

このテンプレートでフォームをレンダリングすると、記事のタイトル、本文、および公開ステータスを選択するためのラジオボタンが表示されます。

このコードを実行すると、以下のようになります。

  1. ユーザーは記事作成ページにアクセスします。
  2. 記事のタイトル、本文、および公開ステータスを選択するためのラジオボタンが表示されます。
  3. ユーザーは記事情報を入力し、公開ステータスを選択します。
  4. ユーザーは「作成」ボタンをクリックします。
  5. 新しい記事がデータベースに保存されます。

この例は、Djangoにおけるforms.RadioSelectの基本的な使用方法を示しています。forms.RadioSelectを使用して、モデルフィールドの選択肢をラジオボタンとしてレンダリングする方法を理解していただけたかと思います。

  • カスタムの選択肢を使用する
class PaymentForm(forms.Form):
    payment_method = forms.ChoiceField(
        choices=(
            ('credit_card', 'クレジットカード'),
            ('paypal', 'PayPal'),
            ('bank_transfer', '銀行振込'),
        ),
        widget=forms.RadioSelect,
        label="支払い方法",
    )
  • Bootstrapを使用してスタイリングする
<div class="form-group">
    {{ form.status.label }}
    {% for choice in form.status.choices %}
        <div class="radio">
            <label>
                {{ choice.label }}
                <input type="radio" name="{{ form.status.name }}" value="{{ choice.value }}" {% if choice.value == form.status.value %}checked{% endif %}>
            </label>
        </div>
    {% endfor %}
</div>


カスタムテンプレートを使用する

最も柔軟性の高い方法は、カスタムテンプレートを使用してラジオボタンをレンダリングすることです。これにより、HTMLとCSSを完全に制御し、デザインを思い通りにカスタマイズできます。

例:

{% for choice in form.field_name.choices %}
  <label for="{{ choice.value }}">
    <input type="radio" id="{{ choice.value }}" name="{{ form.field_name.name }}" value="{{ choice.value }}" {% if choice.value == form.field_name.value %}checked{% endif %}>
    {{ choice.label }}
  </label>
{% endfor %}

crispy_formsを使用する

crispy_formsは、Djangoフォームをよりスタイリッシュにレンダリングするためのライブラリです。crispy_formsを使用すると、ラジオボタンを含むすべてのフォームフィールドを簡単にカスタマイズできます。

from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, RadioField

class MyForm(forms.ModelForm):
    status = forms.ModelChoiceField(
        queryset=MyModel.objects.all(),
        label="ステータス"
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.layout = Layout(
            RadioField('status', label='ステータス')
        )

JavaScriptライブラリを使用する

jQueryBootstrapなどのJavaScriptライブラリを使用して、ラジオボタンを動的に生成およびカスタマイズすることもできます。

<script>
$(document).ready(function() {
  var choices = {{ form.field_name.choices|json }};
  var $radio_buttons = $('<div class="radio-buttons"></div>');

  for (var i = 0; i < choices.length; i++) {
    var choice = choices[i];
    var $radio_button = $('<input type="radio" id="' + choice.value + '" name="' + form.field_name.name + '" value="' + choice.value + '" {% if choice.value == form.field_name.value %}checked{% endif %}>');
    var $label = $('<label for="' + choice.value + '">' + choice.label + '</label>');

    $radio_buttons.append($radio_button);
    $radio_buttons.append($label);
  }

  $('.field-' + form.field_name.name).append($radio_buttons);
});
</script>

サードパーティのウィジェットを使用する

Djangoには、forms.RadioSelect以外にも様々なラジオボタンウィジェットが提供されています。例えば、django_filtersRadioSelectウィジェットは、クエリセットをフィルタリングするためのラジオボタンを生成するのに役立ちます。

カスタムウィジェットを作成する

上記の代替手段がすべて不十分な場合は、独自のウィジェットを作成することができます。これは、高度なカスタマイズが必要な場合に役立ちます。

from django.forms import widgets

class MyRadioSelect(widgets.RadioSelect):
    def render(self, name, value, attrs, choices):
        output = []

        for choice_value, choice_label in choices:
            selected_option = attrs.get('value') == choice_value
            html_choice = '<input type="radio" name="%s" value="%s" %s %s>' % (
                name,
                choice_value,
                (selected_option and 'checked') or '',
                attrs.get('disabled') and 'disabled' or '',
            )
            label_html = '<label for="%s">%s</label>' % (choice_value, choice_label)
            output.append('%s %s' % (html_choice, label_html))

        return mark_safe('\n'.join(output))