Search code examples
pythondjangodjango-widget

How can I write widget for horizontal displaying multiple checkbox?


I have a form with multiple checkbox. But they are vertical displaying by default. I want to display their horizontally. I need to create custom widget for this task. I found a default code of CheckboxSelectMultiple

https://github.com/django/django/blob/master/django/forms/widgets.py#L765

class CheckboxSelectMultiple(ChoiceWidget):
    allow_multiple_selected = True
    input_type = 'checkbox'
    template_name = 'django/forms/widgets/checkbox_select.html'
    option_template_name = 'django/forms/widgets/checkbox_option.html'

    def use_required_attribute(self, initial):
        # Don't use the 'required' attribute because browser validation would
        # require all checkboxes to be checked instead of at least one.
        return False

    def value_omitted_from_data(self, data, files, name):
        # HTML checkboxes don't appear in POST data if not checked, so it's
        # never known if the value is actually omitted.
        return False

    def id_for_label(self, id_, index=None):
        """"
        Don't include for="field_0" in <label> because clicking such a label
        would toggle the first checkbox.
        """
        if index is None:
            return ''
        return super().id_for_label(id_, index)

link to git with django widgets

https://github.com/django/django/tree/master/django/forms/templates/django/forms/widgets

I found also bootstrap form for horizontal displaying multiple checkboxes

{% for ... %}
    <div class="form-check form-check-inline">
      <input type="checkbox" class="form-check-input" id="materialInline{{ .id}}">
      <label class="form-check-label" for="materialInline{{ .id}}">{{ .title}}</label>
    </div>
{% endfor %}

But I don't know how to unite this.


Solution

  • You're looking at the correct thing. As you can see, the default CheckboxSelectMultiple uses these two templates:

    template_name = 'django/forms/widgets/checkbox_select.html'
    option_template_name = 'django/forms/widgets/checkbox_option.html'
    

    So the only thing you need to do is subclass this with your own widget and change the templates to your liking:

    class HorizontalCheckboxSelectMultiple(CheckboxSelectMultiple):
        template_name = 'my_app/widgets/checkbox_select.html'
        option_template_name = 'my_app/widgets/checkbox_option.html'
    

    The checkbox_select.html template is actually the multiple_input.html template which just wraps the group of options (in the default case with a <ul><li>...). The checkbox_option.html template is actually the one to use for each option, where you can put the bootstrap code without the for loop.

    You'll want to look at the input.html template as well which Django includes in the checkbox_option.html template to understand the various widget variables you can use (like widget.name, widget.attrs.id etc...).