Reputation: 3663
In my forms.py
, I have this, where supbplansTuple
is a tuple of tuples:
class RegisterForm(UserCreationForm):
subChoices= forms.ChoiceField(label=_("Choose plan"), widget=forms.RadioSelect, choices=subPlansTuple)
subplansTuple
looks something like this:
(("plan_1234","$5 a month"),("plan_2345","$10 a month"))
register.html
has this:
<form id="register-form" name="regForm" method="post">
{% csrf_token %}
{% for field in registration_form %}
<p>{{ field }}</p>
{% endfor %}
</form>
Problem is, Django displays the radio buttons widget like this:
<p></p>
<ul id="id_subChoices">
<li>
<label for="id_subChoices_0"><input id="id_subChoices_0" name="subChoices" type="radio" value="plan_1234" required=""> $5 a month</label>
</li>
<li>
<label for="id_subChoices_1"><input id="id_subChoices_1" name="subChoices" type="radio" value="plan_2345" required=""> $10 a month</label>
</li>
</ul>
<p></p>
I do not want the radio buttons to display this way. How do I customize the HTML, maybe to look something like Boostrap's inline radio buttons.
Upvotes: 2
Views: 5918
Reputation: 43
Your field object has attributes that allows you to render the inputs in isolation, so in the template you can use the {{field.tag}}
that will render only the field tag and on top you can put a label and inside the label attribute for put the input id {{field.id_for_label}}
. this way:
<form action="" method="post">
{% csrf_token %}
{% for field in registration_form %}
<label for="{{field.id_for_label}}">{{field.choice_label}}</label>
{{field.tag}}
{% endfor %}
</form>
Then we can customize with css
through the classes, using the browser to see their classes in the source code, or defining classes inside the forms class through the attrs property of the RadioButton
class and using it in a css
library, it's all at your discretion. https://docs.djangoproject.com/en/3.1/ref/forms/widgets/#radioselect
Upvotes: 2
Reputation: 304
In Django <1.11 you should write a custom widget render, you can find other solutions in different posts on StackOverflow.
I do not want the radio buttons to display this way. How do I customize the HTML, maybe to look something like Boostrap's inline radio buttons.
Well, the code is quite simple at the end, you'll have to write a little class:
class SwitchRenderer(RadioFieldRenderer):
outer_html = u'{content}'
inner_html = u'{choice_value}{sub_widgets}'
And then use this class as renderer on your widget.
The sample below is another use case that can help.
Django version 1.9.x and I need to implement a radio button like this: https://codepen.io/JiveDig/pen/jbdJXR/
.switch-field {
display: flex;
margin-bottom: 36px;
overflow: hidden;
}
.switch-field input {
position: absolute !important;
clip: rect(0, 0, 0, 0);
height: 1px;
width: 1px;
border: 0;
overflow: hidden;
}
.switch-field label {
background-color: #e4e4e4;
color: rgba(0, 0, 0, 0.6);
font-size: 14px;
line-height: 1;
text-align: center;
padding: 8px 16px;
margin-right: -1px;
border: 1px solid rgba(0, 0, 0, 0.2);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px rgba(255, 255, 255, 0.1);
transition: all 0.1s ease-in-out;
}
.switch-field label:hover {
cursor: pointer;
}
.switch-field input:checked + label {
background-color: #a5dc86;
box-shadow: none;
}
.switch-field label:first-of-type {
border-radius: 4px 0 0 4px;
}
.switch-field label:last-of-type {
border-radius: 0 4px 4px 0;
}
/* This is just for CodePen. */
.form {
max-width: 600px;
font-family: "Lucida Grande", Tahoma, Verdana, sans-serif;
font-weight: normal;
line-height: 1.625;
margin: 8px auto;
padding: 16px;
}
h2 {
font-size: 18px;
margin-bottom: 8px;
}
<form class="form">
<h2>Is this awesome?</h2>
<div class="switch-field">
<input type="radio" id="radio-one" name="switch-one" value="yes" checked/>
<label for="radio-one">Yes</label>
<input type="radio" id="radio-two" name="switch-one" value="no" />
<label for="radio-two">No</label>
</div>
</form>
In order to do this I extended some classes:
class SwitchChoiceInput(RadioChoiceInput):
def render(self, name=None, value=None, attrs=None, choices=()):
if self.id_for_label:
label_for = format_html(' for="{}"', self.id_for_label)
else:
label_for = ''
attrs = dict(self.attrs, **attrs) if attrs else self.attrs
return format_html(
u'{} <label{}>{}</label>', self.tag(attrs), label_for, self.choice_label
)
class SwitchRenderer(RadioFieldRenderer):
choice_input_class = SwitchChoiceInput
outer_html = u'{content}'
inner_html = u'{choice_value}{sub_widgets}'
Finally in the form, I used the renderer created:
field_switch = NullBoleanField(widget=RadioSelect(
choices=[(True, 'Yes') (False, 'No')],
renderer=SwitchRenderer))
I hope the solution helps somebody that like me, arrived on this post.
Upvotes: 1
Reputation: 4839
In Django 1.11+, form widget rendering is done using the template system, so you could override "django/forms/widgets/radio.html", for example.
However, I would recommend using django-crispy-forms. It really helps with controlling the way forms get rendered.
Upvotes: 0