#35126 closed Bug (invalid)
forms.NullBooleanField's validation logic is surprising
Reported by: | Jeremy Lainé | Owned by: | Gaurav sah |
---|---|---|---|
Component: | Forms | Version: | 5.0 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Reading NullBooleanField's code lead me to believe that it would clean "1"
to True
, and "0"
to False
", just like BooleanField
does:
A simple field-level test works:
>>> from django import forms >>> field = forms.NullBooleanField() >>> field.clean("1") True >>> field.clean("0") False
But using this in an actual form fails, note the difference between the BooleanField
and NullBooleanField
:
>>> class DemoForm(forms.Form): ... field_a = forms.BooleanField() ... field_b = forms.NullBooleanField() ... >>> form = DemoForm({"field_a": "1", "field_b": "1"}) >>> form.is_valid() >>> form.cleaned_data {'field_a': True, 'field_b': None}
The problem is that by default NullBooleanField
uses a NullBooleanSelect
which mangles the submitted data for some obscure backwards-compatibility reason:
Change History (6)
comment:1 by , 11 months ago
Description: | modified (diff) |
---|
comment:2 by , 11 months ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:3 by , 11 months ago
Resolution: | → invalid |
---|---|
Status: | assigned → closed |
comment:4 by , 11 months ago
I'm a bit surprised by this answer, it seems somewhat besides the point. I'm not arguing you cannot use other widgets, I'm saying the default widget alters the validation behaviour in an unexpected fashion.
I would expect NullBooleanField to behave exactly like BooleanField for values which normalise to True / False, and validate other values to None. This is exactly what NullBooleanField.to_python expresses too. However this is not the case out of the box: "0" and "1" get validated to None because of what looks like an oversight in NullBooleanWidget.
This was especially surprising in my use case where I don't even use widgets at all, and purely use forms to validate data.
comment:5 by , 11 months ago
Hi Jeremy,
If you'd like, it'd be better to start a discussion either on Discord or on the Django forum as only a limited number of people will see your points raised. Mariusz is quite busy and may be unlikely to respond :) Additionally someone may be able to explain the reasons why NullBooleanSelect diverges in that way.
comment:6 by , 11 months ago
It seems like a useful improvement, if feasible. Jeremy, it would have been most helpful if you did some investigation regarding the backwards compatibility comment rather than simply describing it as "some obscure reason." Using git blame
leads to 35a08b8541c856a51b2ab718e0a2fe060debfa2a (#17210). If you're able to provide a proof of concept solution, feel free to ping me (@timgraham) on a draft GitHub pull request.
It's clearly documented with what kind of widgets (and set of choices) you can use
NullBooleanField()
:I don't see anything to fix here.