장고 양식의 ChoiceField에서 Bootstrap의 btn-group을 사용하고 싶습니다.

하고 싶은 일




・이런 느낌을 RadioSelect의 widget을 사용해 하고 싶었다.
·

환경


  • 장고 3.1.2
  • Bootstrap 4.3.1

  • 전제



    forms.py
    class CustomForm(forms.Form):
        interval = forms.ChoiceField(
            choices=((0, "DAY"), (1, "HOUR"), (2, "MINUTE"),),
            widget=forms.RadioSelect
        )
        ...
    

    이런 Form이 있다고 해서, 이 interval을 위와 같은 Bootstrap의 btn-group을 사용해 표시하고 싶다.

    흐름


  • 설정을 변경하고 RadioSelect에서 자체 Template를 사용할 수 있도록.
  • Template 조정.
  • TestForm에서 자체 Template를 설정합니다.

  • 1. 설정 변경



    settings.py
    FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'
    INSTALLED_APPS [
        ...,
        "django.forms",
    ]
    

    기본 렌더러라면 templates 이하의 파일을 읽을 수 없기 때문에 TemplateSetting으로 변경.
    그리고, 이대로라면 이번에는 임베디드 Template를 읽을 수 없기 때문에 INSTALLED_APPS에 django.forms를 추가.

    2. 자신의 Template 만들기.



    이번에는 Django 디폴트의 것을 베이스로 radio.html 와 radio_options.html 의 2 종류의 Template 를 사용한다.

    widget/radio.html
    {% with id=widget.attrs.id %}
        <div{% if id %} id="{{ id }}"{% endif %}
                        class="btn-group btn-group-toggle {% if widget.attrs.class %}{{ widget.attrs.class }}{% endif %}" data-toggle="buttons">
            {% for group, options, index in widget.optgroups %}
                {% for option in options %}
                    {% include option.template_name with widget=option %}
                {% endfor %}
            {% endfor %}
        </div>
    {% endwith %}
    

    widget/radio_options.html
    {% if widget.wrap_label %}<label{% if widget.attrs.id %}
        for="{{ widget.attrs.id }}"{% endif %}
        class="btn btn-sm btn-outline-dark">{% endif %}{% include "django/forms/widgets/input.html" %}
    {% if widget.wrap_label %} {{ widget.label }}</label>{% endif %}
    

    하고 있는 것은 Class의 추가와 HTML 태그의 수정 정도.

    3. form.py 수정



    forms.py
    class CustomForm(forms.Form):
        interval = forms.ChoiceField(
            choices=((0, "DAY"), (1, "HOUR"), (2, "MINUTE"),),
            widget=forms.RadioSelect
        )
        interval.widget.template_name = "widget/radio.html"
        interval.widget.option_template_name = "widget/radio_options.html"
        ...
    

    [field_name].widget.template_name 과 option_template_name 에 만든 Template를 설정.

    완성!





    Tips



    초기 값을 설정하고 싶습니다.



    forms.py
    class CustomForm(form.Form):
        def __init__(self, *args, **kwargs):
            super(GiftFormSearch, self).__init__(*args, **kwargs)
            self.initial["interval"] = 0
    

    init 내에서 설정할 수 있습니다. views.py에서 설정하고 싶다면 다음과 같습니다.

    views.py
    def hogehoge(request):
        ...
        form = CustomForm({"interval": 0})
    

    다만, input에 checked가 추가되는 것만으로 Class에는 아무것도 추가되지 않기 때문에 외형으로 판별할 수 없는 것에 주의.
    클라이언트 측의 js로 우선 대응하고 있습니다.

    좋은 웹페이지 즐겨찾기