Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django ModelForm doesn't seem to validate BooleanField

I'm using django 1.5.4

Here's a minimal example of the issue I'm facing.

The model:

#models.py
from django.db import models

class SampleModel(models.Model):
    spam = models.BooleanField()

The form:

#forms.py
from django.forms import ModelForm
from .models import SampleModel

class SampleModelForm(ModelForm):
    class Meta:
        model = SampleModel
        fields = ('spam', )

From the django shell:

>>> data = {} #intentionally blank
>>> form = SampleModelForm(data)
>>> is_valid = form.is_valid() #is_valid is True
>>> form.save() # model instance is created with "spam" set to False by default.

Am I validating the form incorrectly? form.is_valid validates fields of other types correctly. The docs indicate that all fields are required by default but is_valid returns Truewithout the boolean field key being present.

I need to ensure that the boolean field is present in the input data. As of now, I'm manually checking if the field is present and is of type bool. Do you think I should override form.is_valid and add this check so that it can be reused for other models too?

like image 935
Pramod Avatar asked Mar 22 '23 02:03

Pramod


1 Answers

It turns out (from code inspection; the docs don't say) that model BooleanFields have blank=True set automatically in their __init__ method, thus making the automatically created model form field not required. This makes sense upon consideration (False counts as blank, so BooleanFields need it to be true) but it's not obvious when you just read the docs.

If you want it to be required to be True, the usual form field overrides apply - declare the field yourself or set its required attribute to be True somewhere before validating (I usually use the form's __init__ method). If you want it to allow True or False but not Python None, it's harder.

Specifically, the standard widget for a BooleanField is a checkbox. Browsers do not submit anything for unchecked checkboxes, so the checkbox widget treats the absence of the field from the submit as False. There's no way to distinguish the user not selecting the checkbox from cases in which the input really is bad. You could use a different widget (say, a RadioSelect) to at least make it possible for the browser to submit something for False, but you still have the problem that the BooleanField's to_python method converts its value to a boolean before validating, so you'd have to subclass and override.

Fortunately, False is not considered empty by the validation code, so if you do that you'll be able to set required=True and don't need custom cleaning methods.

like image 83
Peter DeGlopper Avatar answered Apr 24 '23 05:04

Peter DeGlopper