Opened 10 years ago

Closed 10 years ago

#22282 closed Uncategorized (needsinfo)

models.BooleanField.blank should be 'False' if BooleanField has choices

Reported by: django@… 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 set blank=True if kwargs.get('blank') is None
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 is False and not None (OK, I'm assuming somewhere that BooleanField converts a None value to False?
  • 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?

Change History (1)

comment:1 by Aymeric Augustin, 10 years ago

Resolution: needsinfo
Status: newclosed

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 set blank = False. If it's optional, you set blank = 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 that blank = 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 a ValidationError.

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 getting True or an execption isn't interesting at the model layer.

I'm not sure where "BooleanField assumes a None value to be False" 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!

Note: See TracTickets for help on using tickets.
Back to Top