Permalink
Browse files

[1.5.x] Fixed #16820 -- Treated '0' value as True for checkbox inputs

Thanks Dan Fairs for the report and the initial patch.

Backport of be29329 from master.
  • Loading branch information...
1 parent 02b66f1 commit fbb664066f8970279af020cf163cb364156290c3 @claudep claudep committed Oct 26, 2012
View
2 django/forms/widgets.py
@@ -528,7 +528,7 @@ def value_from_datadict(self, data, files, name):
values = {'true': True, 'false': False}
if isinstance(value, six.string_types):
value = values.get(value.lower(), value)
- return value
+ return bool(value)
def _has_changed(self, initial, data):
# Sometimes data or initial could be None or '' which should be the
View
5 tests/regressiontests/forms/tests/forms.py
@@ -269,6 +269,11 @@ class SignupForm(Form):
f = SignupForm({'email': 'test@example.com', 'get_spam': 'false'}, auto_id=False)
self.assertHTMLEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" />')
+ # A value of '0' should be interpreted as a True value (#16820)
+ f = SignupForm({'email': 'test@example.com', 'get_spam': '0'})
+ self.assertTrue(f.is_valid())
+ self.assertTrue(f.cleaned_data.get('get_spam'))
+
def test_widget_output(self):
# Any Field can have a Widget class passed to its constructor:
class ContactForm(Form):
View
4 tests/regressiontests/forms/tests/widgets.py
@@ -225,6 +225,10 @@ def test_checkboxinput(self):
# checkboxes).
self.assertFalse(w.value_from_datadict({}, {}, 'testing'))
+ value = w.value_from_datadict({'testing': '0'}, {}, 'testing')
+ self.assertIsInstance(value, bool)
+ self.assertTrue(value)
+
self.assertFalse(w._has_changed(None, None))
self.assertFalse(w._has_changed(None, ''))
self.assertFalse(w._has_changed('', None))

2 comments on commit fbb6640

@timgraham
Django member

This is backwards incompatible in that I have the following code for an API which relies on the checkbox input returning the actual submitted value:

class BooleanChoiceField(forms.BooleanField):

    def clean(self, value):
         if value in (False, 'False', 'false', '0'):
            value = False
        elif value in (True, 'True', 'true', '1'):
            value = True
        else:
            raise ValidationError("Invalid choice '%s' for boolean field." % value)
        return value

Now value_from_datadict returns True for something like 'bad input'

Do you think I should rewrite my code with a different widget or should we made a change to Django itself?

@claudep
Django member

Hi Tim,
Basically, I think that a BooleanField should return a boolean value. If you have a different specific need, I'd suggest you just subclass the form field and redefine clean(). Post on the ticket if you'd like some larger audience.

Please sign in to comment.