Opened 11 years ago
Closed 11 years ago
#22282 closed Uncategorized (needsinfo)
models.BooleanField.blank should be 'False' if BooleanField has choices
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.6 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | yes | UI/UX: | no |
Description
There's no way to override the 'blank' property on a boolean field.
If you look at db/models/fields/init.py under BooleanField.__init__()
you'll see that blank = True
is hard coded.
This gets messy for a couple of reasons:
- It means that doing something like this silently fails. Either it should raise an error (e.g. "blank cannot be set for BooleanField") or in
__init__
do a check to only setblank=True
ifkwargs.get('blank')
isNone
class MyObj(models.Model): is_good = models.BooleanField(blank=False) # fails silently since blank = True is hard coded
- It makes me question the strictness of the
blank
property, if a boolean field in a form can validate when in fact it isFalse
and notNone
(OK, I'm assuming somewhere that BooleanField converts aNone
value toFalse
?
- Most importantly (and the case where this broke for me) is when I wanted to do something like:
class MyObj(models.Model): is_good = models.BooleanField(choices=( (False, "Object is Bad"), (True, "Object is Good") )
There's no way to make sure the value is not blank.
My simple fix was to edit BooleanField
's __init__
method to do:
def __init__(self, *args, **kwargs): if not kwargs.get('choices'): kwargs['blank'] = True Field.__init__(self, *args, **kwargs)
But now I think about it maybe the fact that BooleanField
assumes a None
value to be False
is another problem as well. I know why - because the default widget is a tickbox, which have the same state for None
and False
- but maybe the converting of None
to False
should consider the widget type?
Let's start with form fields. A
BooleanField
is rendered by default as a checkbox. If it's mandatory (e.g. accept terms & conditions), you setblank = False
. If it's optional, you setblank = True
.Let's now look at model fields. Only the second case makes sense. That's why Django forces
blank = True
. You're right, Django could warn thatblank = False
is a misconfiguration that probably doesn't do what you expect.If I understand correctly, you'd like to use a different widget, maybe a radio list with two choices. If a value that doesn't match either of your choices is returned, as far as I can tell,
BooleanField.to_python
is going to raise aValidationError
.I don't understand why you're saying that "There's no way to make sure the value is not blank." On the contrary, Django enforces that you always get
True
,False
or an exception at the model layer. As explained above, always gettingTrue
or an execption isn't interesting at the model layer.I'm not sure where "
BooleanField
assumes aNone
value to beFalse
" comes from either.Could you show why your example doesn't work? Either an exception traceback or a failing test case will do. Thank you!