Django form with just a BooleanField

This also works for me on 1.1, 1.0.3 and 1.0 (I have these three Virtual environments setup). I only tested this in FireFox so if its a browser issue thats another matter but as far as I know they all handle POST data with checkboxes the same.

Here is the full code for the project so you can reproduce at your leisure and compare with yours to see the difference.

Setting up in Ubuntu

$ django-admin.py startproject testing
$ cd testing/
$ python manage.py startapp myfirst

Then in the myfirst app folder;

/myfirst/views.py

from django.shortcuts import render_to_response

from myfirst.forms import MyForm

def testing(request):
    if request.method == 'POST':
        form = MyForm(request.POST)
        if form.is_valid():
            result = "valid"
        else:
            result = "not valid"
    else:
        form = MyForm()
        result = "no post"

    return render_to_response('test.html', {'form':form, 'result':result,})

/myfirst/forms.py from django import forms

class MyForm(forms.Form):
    extra_cheeze = forms.BooleanField(required=False,initial=False,label='Extra cheeze')

/myfirst/templates/test.html

<html>
<head>
</head>
<body>
    <form action="." method="POST">
        {{ form }}
        <input type="submit" value="test">
    </form>
    {{ result }}
</body>
</html>

/urls.py from django.conf.urls.defaults import *

from myfirst.views import testing

urlpatterns = patterns('',
     (r'.*', testing),
)

Then just run the project $ python manage.py runserver and browse to http://localhost:8000/. You'll actually find that required doesn't do anything with the checkbox, since you can't leave it blank - a 'blank' answer is effectively 'no'. If you want to make sure a user selects an answer have a multiple choice where the user has to select yes or no. You could force them to answer with radio buttons too.


There was a bug in the code in my question. Thanks to @d0ugal for helping me spot it by including a slightly different example. The problem was here:

form = MyForm(request.POST or None) # <- PROBLEM HERE!!!!!!!!!!!!!!!!
if request.method == 'POST' and form.is_valid():
    # do stuff...

The bug was that I assumed that request.POST would evaluate to True if it was a post. But since browsers don't post anything for a not-checked checkbox, and that was the only field, the POST data was an empty dictionary, which evaluates to False. This caused None to be used as initialization data, causing the form to be unbound and not valid.
@d0ugal's example does the safe thing and tests request.method first.