How to prevent django fields from being wrapped in a `div`?

Question:

If I use the below to generate multiple radio buttons:

from django import forms


class MCQCollectionForm(forms.Form):
    user_input = forms.ChoiceField(
        widget=forms.RadioSelect, label='', choices=enumerate(['option 1', 'option 2'])
    )

I get:

<div id="id_user_input">
    <div>
        <label for="id_user_input_0"><input id="id_user_input_0" name="user_input" required="" type="radio"
                                            value="0">
            option 1</label>

    </div>
    <div>
        <label for="id_user_input_1"><input id="id_user_input_1" name="user_input" required="" type="radio"
                                            value="1">
            option 2</label>

    </div>
</div>

but I want it to be only the below, nothing else:

<label class="user-item">
    <input name="user_input" type="radio" ... >
    <span>Lorem ipsum dolor</span>
</label>
<label class="user-item">
    <input name="user_input" type="radio" ... >
    <span>Lorem ipsum dolor</span>
</label>

is there a simple way to do so without having to use JS and manually make the desired changes? Note: the extra attributes id=..., required, … are fine, I just want the divs gone and be able to add a class to the label and span with its contents.

Asked By: nlblack323

||

Answers:

You can do it by using a custom widget inherited from forms.RadioSelect and overriding the method create_option

In your forms.py file add this custom widget class.

class CustomRadioSelect(forms.RadioSelect):
    def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
        option = super().create_option(name, value, label, selected, index, subindex, attrs)
        option["wrapper_attrs"] = {}
        if "label_attrs" not in option:
            option["label_attrs"] = {}
        option["label_attrs"]["class"] = "user-item"
        return option

Now, Update your MCQCollectionForm class with this:

class MCQCollectionForm(forms.Form):
    user_input = forms.ChoiceField(
        widget=CustomRadioSelect, label='', choices=enumerate(['option 1', 'option 2'])
    )

From your views.py file pass the form through your appropriate view context like: form = MCQCollectionForm() render(.....,{'form':form})
(I believe you already have this in place)

From your template file loop through the form fields like below:

{% for choice in form1.user_input %}
    <label class="{{ choice.label.attrs.class }}" for="{{ choice.id_for_label }}">
    {{ choice.tag }}
       <span>{{ choice.choice_label }}</span>
     </label>
{% endfor %}

This will help you to achieve your goal. Below is a screenshot of how it will format in HTML source code.

django form custom widget

Answered By: dostogircse171
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.