HI
I want to align the radio buttons horizontally. By default django forms displays in vertical format.
feature_type = forms.TypedChoiceField(choices =
On my Django 2.2.6 above solutions did not worked well, so I post my solution after many tries and following the breadcrumbs until the django forms widget templates used.
I had to override 2 templates, and heritage my own widget class and then point it.
The modified default django templates have been:
Now they are:
PROJECT_NAME/PROJECT_APP/templates/admin/horizontal_option.html
{% if widget.wrap_label %}<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %} class="radio-inline">{% endif %}{% include "django/forms/widgets/input.html" %}{% if widget.wrap_label %} {{ widget.label }}</label>{% endif %}
PROJECT_NAME/PROJECT_APP/templates/admin/horizontal_radios.html
{% with id=widget.attrs.id %}<ul{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>{% for group, options, index in widget.optgroups %}{% if group %}
<li>{{ group }}
<ul{% if id %} id="{{ id }}_{{ index }}"{% endif %}>{% endif %}{% for option in options %}
{% include option.template_name with widget=option %}{% endfor %}{% if group %}
</ul></li>{% endif %}{% endfor %}
</ul>{% endwith %}
class="radio-inline"
at labels, which in default Django had nothingThen you need to create your own widget class:
from django.forms import RadioSelect
class HorizontalRadioSelect(RadioSelect):
template_name = 'admin/horizontal_radios.html'
option_template_name = 'admin/horizontal_inputs.html'
And finally, in my case, I pointed to it overriding formfield_overrides
class attribute in my admin. But you can do this in your models too I think:
formfield_overrides = {
models.BooleanField: {'widget': HorizontalRadioSelect(choices=[(True, "Yes"), (False, "No"), (None, "Unknown")],)},
}
According to the Django docs 'attrs' is a dictionary containing HTML attributes to be set on the rendered widget.
With that in mind a simple form based solution would be something like the following:
feature_type = forms.TypedChoiceField(
choices = formfields.FeatureType,
widget = forms.RadioSelect(attrs={
'style': 'display: inline-block'
})
)
There is actually no need to override the widget, template or anything else in admin. At least since 2008 (see forms.css), the easiest way is to pass a class attribute inline
: attrs={'class': 'inline'}
In a custom form, it may look like:
field = forms.ChoiceField(choices=(('1', 'one'), ('2', 'two')),
widget=forms.RadioSelect(attrs={'class': 'inline'}))
… and it works the very same for checkboxes:
field = forms.MultipleChoiceField(choices=(('1', 'one'), ('2', 'two')),
widget=forms.CheckboxSelectMultiple(attrs={'class': 'inline'}))
And it should be the very same for formfield overrides, either via ModelAdmin formfield_overrides
or formfield_for_*
functions.
Thats the behavior of the RadioField
. If you want it rendered horizontally, create a horizontal renderer, like something as follows:
from django.utils.safestring import mark_safe
class HorizontalRadioRenderer(forms.RadioSelect.renderer):
def render(self):
return mark_safe(u'\n'.join([u'%s\n' % w for w in self]))
class ApprovalForm(forms.Form):
approval = forms.ChoiceField(choices=APPROVAL_CHOICES,
initial=0,
widget=forms.RadioSelect(renderer=HorizontalRadioRenderer),
)
Another way out is to changing the style of ul->li list to display:inline-block. You can do something like that
<style>
ul#youelementId li{
display: inline-block;
}
</style>
hope this would help next reader.
I've come up with an alternative solution. If you are using bootstrap to render your forms, you can add the .form-check-inline class to the input and the field will display horizontally. Listed below is code that shows what I'm describing. I hope this helps someone from reinventing the wheel. Thanks for reading. Take care and have a good day.
feature_type = forms.MultipleChoiceField(
required=False,
...
widget=forms.CheckboxSelectMultiple(attrs={'class': 'form-check-inline'})
)