Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - use Radio Buttons instead of Select for form component

Tags:

python

django

I have several ModelForms used to build surveys, whose models contain lots of questions (>30 each). At the moment, the multiple choice questions are represented as a <select> element, but to improve UX I'd like to change this to radio buttons.

As it's a ModelForm, I rely on django to automatically create the fields on the form. So while I know it's possible to change each field on the form by doing this:

class SurveyForm(ModelForm):
   ...
   field_one = forms.ChoiceField(choices=CHOICES, widget=forms.RadioSelect())

these definitions don't currently exist, and I'd have to create at least 150 of those definitions. I'm sure there's a better way to override where the widget choice is made (perhaps extending ModelForm?). Or alternatively, could I do this by attaching the widget to the field definition?

I've taken a look through the Django docs and source, but I can't find where the widget is chosen for model fields with a choices kwarg.

like image 861
jackweirdy Avatar asked Jul 21 '15 12:07

jackweirdy


2 Answers

class MyModelForm(ModelForm):
    class Meta:
        widgets = {
            'field_one': forms.RadioSelect(),
        }

May be you'd like this:

widgets = {field: forms.RadioSelect() for field in ['field_one', 'field_two']}
like image 121
f43d65 Avatar answered Nov 14 '22 23:11

f43d65


My first thought was that you could use formfield_overrides. However, that won't work, because you only want to override the widget for models.CharFields that have choices, not all models.CharFields.

One approach would be to loop through the form's fields in the __init__ method, and change any widgets from forms.Select to forms.RadioInput.

class SurveyForm(forms.ModelForm):
    class Meta:
        model = Survey
        fields = ('field_one', 'field_two', ...)

    def __init__(self, *args, **kwargs):
        super(SurveyForm, self).__init__(*args, **kwargs)
        for field in self.fields.values():
            if isinstance(field.widget, forms.Select):
                field.widget = forms.RadioSelect()

If you have many forms like this, you could extract the functionality into a mixin.

like image 20
Alasdair Avatar answered Nov 15 '22 00:11

Alasdair