views:

2971

answers:

5

Is there a widget in Django 1.0.2 to render a models.BooleanField as two radio buttons instead of a checkbox?

+15  A: 

You could do this by overriding the field definition in the ModelForm:

class MyModelForm(forms.ModelForm):
    boolfield = forms.TypedChoiceField(coerce=bool,
                   choices=((False, 'False'), (True, 'True')),
                   widget=forms.RadioSelect
                )

    class Meta:
         model = MyModel
Daniel Roseman
Unfortunately this didn't work, because the coerce=bool is being passed a string value, and not the boolean value and bool("False") => True. So I had to write a custom coerce function to take the string value and convert to bool, then it worked. Thanks for the pointer.
dar
+1  A: 

Also remember that MySQL uses tinyint for Boolean, so True/False are actually 1/0. I used this coerce function:

def boolean_coerce(value):
    # value is received as a unicode string
    if str(value).lower() in ( '1', 'true' ):
        return True
    elif str(value).lower() in ( '0', 'false' ):
        return False
    return None
Denilson Sá
+9  A: 

Modifying Daniel Roseman's answer a bit, you could fix the bool("False") = True problem succinctly by just using ints instead:

class MyModelForm(forms.ModelForm):
    boolfield = forms.TypedChoiceField(coerce=lambda x: bool(int(x)),
                   choices=((0, 'False'), (1, 'True')),
                   widget=forms.RadioSelect
                )

class Meta:
     model = MyModel
Thank you very much, you just saved me a lot of work!
Jannis
A: 

Here's a quick & dirty coerce function using lambda, that gets around the "False" -> True problem:

...
boolfield = forms.TypedChoiceField(coerce=lambda x: x and (x.lower() != 'false'),
...
funksta
A: 

Django 1.2 has added the "widgets" Meta option for modelforms:

In your models.py, specify the "choices" for your boolean field:

BOOL_CHOICES = ((True, 'Yes'), (False, 'No'))

class MyModel(models.Model):
    yes_or_no = models.BooleanField(choices=BOOL_CHOICES)

Then, in your forms.py, specify the RadioSelect widget for that field:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'yes_or_no': forms.RadioSelect
        }

I've tested this with a SQLite db, which also stores booleans as 1/0 values, and it seems to work fine without a custom coerce function.

eternicode