Django form with BooleanField always invalid unless checked

I have an application that uses the following form:

class ConfirmForm(forms.Form):
    account_name = forms.CharField(widget=forms.HiddenInput)
    up_to_date = forms.BooleanField(initial=True)

I use the form in the following template exerpt:

<form class="confirmform" action="/foo/" enctype="multipart/form-data" method="post">
{{ confirm_form.up_to_date }} Check if this data brings the account up to date.<br>
{{ confirm_form.account_name }} <input type="submit" name="confirm" value="Confirm" />
</form>

My view uses the following basic code structure:

if request.method == 'POST':
    #check for 'confirm' because I actually have multiple forms in this page
    if 'confirm' in request.POST:
        confirm_form = ConfirmForm(request.POST)
        if confirm_form.is_valid():
            #do stuff
        else:
            c['confirm_form'] = confirm_form
else:
    c['confirm_form'] = ConfirmForm({'account_name':'provided_value'})

Two things are wrong:

1) Even though I have initial=True, the checkbox is unchecked when the page loads

2) The form is always invalid unless I check the checkbox. It gives errors for up_to_date only: "This field is required."

I have read this similar question but his solution doesn't apply to my project.

So... what's going on?

Edit:

I updated the code above to be more faithful to my actual code.

Problem #1 was my fault because I was overriding the initial value by binding data when the form was instantiated.

Problem #2 I still consider an issue. Using required=False on up_to_date will fix the problem, however it doesn't seem correct that using the default widget, a BooleanField can be either NULL (causes validity check to fail) or True but never False.


In Django forms, Boolean fields must be created with required=False.

When the checkbox isn't checked, browsers do not send the field in the POST parameters of requests. Without specifying that the field is optional Django will treat it as a missing field when not in the POST parameters.

Imho it would be nice for Django to have this behavior by default for boolean form fields..

(this was already answered in comments by Yuji but it would be useful as an answer)


initial=True should render the widget with checked="checked" so I don't see the problem there.. but the reason the form is invalid is because all fields are required by default unless you specify otherwise.

Field.required¶ By default, each Field class assumes the value is required, so if you pass an empty value -- either None or the empty string ("") -- then clean() will raise a ValidationError exception:

If you'd like a checkbox or any other value to be optional, you need to pass in required=False into the form field constructor.

up_to_date = forms.BooleanField(initial=True, required=False) 
# no longer required..

According to official docs:

If you want to include a boolean in your form that can be either True or False (e.g. a checked or unchecked checkbox), you must remember to pass in required=False when creating the BooleanField.


Just a hunch, but this could be about the basics - lost a few hours until realising something similar was just about basic variable types.

In my case, after creating the FORM (very basic, see below)

class para_selection(forms.Form):
    first=forms.BooleanField(initial=False, required=False)
    second=forms.BooleanField(initial=False, required=False)
    third=forms.BooleanField(initial=False, required=False)
    fourth=forms.BooleanField(initial=False, required=False)

... I was using if selection == 'True': .. in my view. But since the form is using Boolean values, the correct code would be: if selection is True:

The first line will never work, because "==" is not used with Boolean type. Hopefully this was not the case, but wanted to flag it here since I kept trying and searching all over the Internet, without paying attention to the type of variable I was using.