Django BooleanField as radio buttons?

DjangoDjango ModelsDjango Forms

Django Problem Overview


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

Django Solutions


Solution 1 - Django

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.

Solution 2 - Django

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

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

    class Meta:
         model = MyModel

Solution 3 - Django

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

Solution 4 - Django

Here's the simplest approach I could find (I'm using Django 1.5):

class MyModelForm(forms.ModelForm):
    yes_no = forms.BooleanField(widget=RadioSelect(choices=[(True, 'Yes'), 
                                                            (False, 'No')]))

Solution 5 - Django

In Django 1.6, the following worked for me:

class EmailSettingsForm(ModelForm):

    class Meta:
	    model = EmailSetting
	    fields = ['setting']
	    widgets = {'setting': RadioSelect(choices=[
		    (True, 'Keep updated with emails.'),
		    (False, 'No, don\'t email me.')				
		])}

Solution 6 - Django

Same as @eternicode's answer, but without modifying the model:

class MyModelForm(forms.ModelForm):
    yes_no = forms.RadioSelect(choices=[(True, 'Yes'), (False, 'No')])

    class Meta:
        model = MyModel
        widgets = {'boolfield': yes_no}

I think this only works in Django 1.2+

Solution 7 - Django

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'),
...

Solution 8 - Django

As there is problem in @Daniel Roseman answer, bool('False') --> True, so now i have combined two answers here to make one solution.

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

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

class Meta:
     model = MyModel

Now this will work :)

Solution 9 - Django

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

Solution 10 - Django

An other solution:

from django import forms
from django.utils.translation import ugettext_lazy as _

def RadioBoolean(*args, **kwargs):
    kwargs.update({
        'widget': forms.RadioSelect,
        'choices': [
            ('1', _('yes')),
            ('0', _('no')),
        ],
        'coerce': lambda x: bool(int(x)) if x.isdigit() else False,
    })
    return forms.TypedChoiceField(*args, **kwargs)

Solution 11 - Django

update for django version 3.0:

BOOLEAN_CHOICES = (('1', 'True label'), ('0', 'False label'))
  # Filtering fields
    True_or_false_question = forms.ChoiceField(
        label="Some Label3",
  # uses items in BOOLEAN_CHOICES
        choices = BOOLEAN_CHOICES,
        widget = forms.RadioSelect
    )

it gives a bullet point button list, i dont know how to make it not do that

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondarView Question on Stackoverflow
Solution 1 - DjangoeternicodeView Answer on Stackoverflow
Solution 2 - DjangoDaniel RosemanView Answer on Stackoverflow
Solution 3 - DjangoChristian AbbottView Answer on Stackoverflow
Solution 4 - DjangoRacing TadpoleView Answer on Stackoverflow
Solution 5 - DjangoKevin WhiteView Answer on Stackoverflow
Solution 6 - DjangoyprezView Answer on Stackoverflow
Solution 7 - Djangoaf__View Answer on Stackoverflow
Solution 8 - DjangoAhsanView Answer on Stackoverflow
Solution 9 - DjangoDenilson Sá MaiaView Answer on Stackoverflow
Solution 10 - DjangomatinfoView Answer on Stackoverflow
Solution 11 - Djangoanthony pizarroView Answer on Stackoverflow