I didn't expect creating a radio input in a form using Bootstrap3's style could have some many pitfalls.
Here is a model I have:
class UserProfile(models.Model):
GENDER_CHOICES = (('M', 'Male',), ('F', 'Female',))
fullname = models.CharField(u'Name', max_length=10)
sex = models.CharField(u'Gender', max_length=1, choices=GENDER_CHOICES)
# ... and 11 other fields
Here is the corresponding ModelForm:
from django.forms.widgets import RadioSelect
class UserProfileForm(ModelForm):
class Meta:
model = UserProfile
widgets = {
'sex': forms.RadioSelect()
}
I have a sex field which let users to pick their gender. When running the code above, I get three choices instead of two:
- '--------' # django automatically insert this 'default' option
- 'Male'
- 'Female'
This is of course not what we want. There should only be two options, 'Male' and 'Female'. So to correct this issue, I had to add TWO extra parameters to the Model:
sex = models.CharField(u'Gender', max_length=1, choices=GENDER_CHOICES, blank=False, default='M')
Note that I added blank=False AND default='M'. If you only include blank=False, you will still see the '--------' option. It is important to have both of them set.
Now, I want to style my forms using Bootstrap3. To do this, I recommend using crispy-forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from crispy_forms.bootstrap import InlineRadios
class UserProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.method = 'post'
self.helper.form_action = 'index'
self.helper.layout.append(Submit('save', 'Save'))
class Meta:
model = UserProfile
Crispy-form creates a Bootstrap3 style input field for every single field defined in the model when this line runs:
self.helper = FormHelper(self)
The UserProfile model has 13 fields. It is nice that I don't have to specify each one of the 13 fields. But here comes the problem, when the radio input is been rendered. The male and female options are listed vertically. I want them to be listed horizontally. Crispy-form does provide an inline option for rendering radio inputs horizontally. This is nice, but how can I replace the default Layout of the gender field with the suggested inline Layout?
self.helper[1] = InlineRadios('sex')
Crispy-forms allows you to access the Layout of each field by using index.
With the tweaks above, now I have a wonderful radio input for gender selection :) So many small things need to be taken care of for something seems so trivial.