Question

I am successfully implementing NullBooleanField as radio buttons in several ways but the problem is that I can not set the default value to None.

Here is the code:

models.py:
class ClinicalData(models.Model):
      approved = models.NullBooleanField()
      ...

forms.py:
NA_YES_NO = ((None, 'N/A'), (True, 'Yes'), (False, 'No'))
class ClinicalDataForm(ModelForm):
      approved = forms.BooleanField(widget=forms.RadioSelect(choices=NA_YES_NO))
      class Meta:
           model = ClinicalData 

I tried the following methods: Set default:None in the model and/or setting inital:None in the form and also in the view in the form instance.
None of that was successfull. Im currently using CharField instead of NullBooleanField.
But is there some way to get this results with NullBooleanField???

Was it helpful?

Solution

For some odd reason - I didn't check it at the Django code -, as soon as you provide a custom widget for a NullBooleanField, it doesn't accept the values you expect (None, True or False) anymore.

By analyzing the built-in choices attribute, I found out that those values are equal to, respectively, 1, 2 and 3.

So, this is the quick-and-dirty solution I fould to stick to radio buttons with 'Unknown' as default:

class ClinicalDataForm(forms.ModelForm):
    class Meta:
        model = ClinicalData

    def __init__(self, *args, **kwargs):
        super(ClinicalDataForm, self).__init__(*args, **kwargs)
        approved = self.fields['approved']
        approved.widget = forms.RadioSelect(
            choices=approved.widget.choices)
        approved.initial = '1'

It doesn't look good and I wouldn't use it unless very necessary. But there it is, just in case.

OTHER TIPS

I know this has been answered for a while now, but I was also trying to solve this problem and came across this question.

After trying emyller's solution, it seemed to work, however when I looked at the form's self.cleaned_data, I saw that the values I got back were all either True or None, no False values were recorded.

I looked into the Django code and saw that while the normal NullBooleanField select does indeed map None, True, False to 1, 2, 3 respectively, the RadioSelect maps 1 to True, 0 to False and any other value to None

This is what I ended up using:

my_radio_select = forms.NullBooleanField(
    required=False,
    widget=widgets.RadioSelect(choices=[(1, 'Yes'), (0, 'No'), (2, 'N/A')]),
    initial=2,  # Set initial to 'N/A'
)

For what it's worth, the other answers given here no longer apply in Django 1.7. Setting choices to [(True, "Yes"), (False, "No"), (None, "N/A")] works just fine.

For me in Django 1.7 None value is not selected by default (despite what Craig claims). I subclassed RadioSelect, it helped in my case:

from django.forms.widgets import RadioSelect
from django.utils.translation import ugettext_lazy

class NullBooleanRadioSelect(RadioSelect):
    def __init__(self, *args, **kwargs):
        choices = (
            (None, ugettext_lazy('Unknown')),
            (True, ugettext_lazy('Yes')),
            (False, ugettext_lazy('No'))
        )
        super(NullBooleanRadioSelect, self).__init__(choices=choices, *args, **kwargs)

    _empty_value = None

I've achieved this with Django 2.2.

You should be able to have the None radio option checked with a ChoiceField and RadioSelect widget. The trick is to set the None choice value to empty string ''.

The model field I used was a BooleanField with null=True which is essentially the same as the model field NullBooleanField.

approved = forms.ChoiceField(
    choices=[(True, 'Yes'), (False, 'No'), ('', 'N/A')],
    widget=forms.RadioSelect,
    required=False,
)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top