Query on BooleanField with values other than True and False, bug or intentional?

5,059 views
Skip to first unread message

Kaveh Karimi

unread,
Jan 22, 2016, 2:51:41 PM1/22/16
to Django developers (Contributions to Django itself)
Today I discovered I can use strings and numbers to query on BooleanFields.

Let's say we have the following model:

class Whatever(models.Model):
    name
= models.CharField(max_length=200)
    is_active
= models.BooleanField()

The following queries return all instances which their `is_active` field is True:

Whatever.object.filter(is_active=True)
Whatever.object.filter(is_active='some_random_text')
Whatever.object.filter(is_active=777)

and the followings return the ones which are False:

Whatever.object.filter(is_active=False)
Whatever.object.filter(is_active='')
Whatever.object.filter(is_active=0)

Is this behaviour intentional or is it a bug? Should queries on BooleanFields accept strings and numbers?

Tim Graham

unread,
Jan 22, 2016, 3:57:38 PM1/22/16
to Django developers (Contributions to Django itself)
It doesn't seem to me that changing the behavior at this point is worth possible backwards incompatibilities.

Maxime Lorant

unread,
Jan 22, 2016, 4:18:45 PM1/22/16
to Django developers (Contributions to Django itself)
At least, the behaviour is predictable : it uses `bool(value)`. I believe it is not a bug but more a question about the input definition: should we allow non boolean value? I don't see any problem here accepting a string as a `True` value, it is the job of the user to ensure the value is castable to a boolean.

The same behaviour is found on `IntegerField` for example: `Model.objects.filter(pk="foo")` raises `ValueError: invalid literal for int() with base 10: 'foo'` which implies the ORM tried to cast 'foo' as an integer.

sbrandt

unread,
Jan 23, 2016, 2:42:08 AM1/23/16
to Django developers (Contributions to Django itself)
I agree on the "it is the job of the user" thing as well as on the predictability on IntegerField, but there is at least one case where this goes horribly wrong. Imagine in the web-world we are receiving JSON and for some case, the browser sends "false" as a string. `bool('false') -> True`.

One could say this is again a mistake of the app developer, but my understanding of "explicit is better than implicit" is that Django should explicitly protect me from those mistakes that could stay undetected for a very long time because it just happily silently implicitly converts data types like PHP.

Maybe a backwards compatible solution here would be to provide an `strict=False` parameter to model fields or provide `StrictIntegerField` etc subclasses, although this may end up in a mess.

Chris Foresman

unread,
Jan 29, 2016, 5:37:51 PM1/29/16
to Django developers (Contributions to Django itself)
I have to agree here; it's pretty sloppy to not enforce an explicit boolean value and can lead to subtle bugs. In addition to the one mentioned by Maxime, consider the case of a nullable boolean field:

>>> bool(None)
False

Maybe that field has a better converter for possible values and explicitly allows `None`, but I think it would be fairly trivial to add a stricter check and pretty easy to fix code that's not backwards compatible with find/replace.

Chris Foresman

unread,
Jan 29, 2016, 5:38:52 PM1/29/16
to Django developers (Contributions to Django itself)
Sorry, sbrandt noted the issue of subtle bugs, not Maxime.

Adam Johnson

unread,
Jan 31, 2016, 4:34:36 AM1/31/16
to Django developers (Contributions to Django itself)
Just to play devil's advocate... you're all worrying about one simple case; there are infinite variants of it with subtle bugs, for example imagine the same situation but with Value:

Whatever.object.filter(is_active=Value('false'))

The ORM can't predict the type of a Value call - pretty much by definition, since it's a raw value passed to the database. So you might be able to fix BooleanField for a few cases, but you can't fix them all..

Hanne Moa

unread,
Feb 2, 2016, 5:23:37 AM2/2/16
to django-d...@googlegroups.com
I don't think enforcing it would be pythonic.

Once upon a time, Python lacked True and False, all you had were
truthy and falsey and maybe per-project/team constants:

http://python-history.blogspot.no/2013/11/story-of-none-true-false.html

I remember the arguments when bool() was added. Those against were
worried that it would send a signal that would lead to a slippery
slope where truthy and falsey would disappear because people would
insist that "it's pretty sloppy to not enforce an explicit boolean
value and can lead to subtle bugs".

Well..
> --
> You received this message because you are subscribed to the Google Groups
> "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-develop...@googlegroups.com.
> To post to this group, send email to django-d...@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-developers.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-developers/ec95ccb7-5ca0-410c-a52b-1ccf75f5d766%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.

Chris Foresman

unread,
Feb 4, 2016, 1:17:30 AM2/4/16
to Django developers (Contributions to Django itself)
I don't think that's the same thing. We're talking about interfacing with a system that has clearly delineated values.
The boolean type can have several states: "true""false", and a third state, "unknown", which is represented by the SQL null value.[1]

While the database accepts a variety of optional string literals to insert true or false, none of them are truly comparable to Python's truth-y or false-y values. For instance, psycopg2 only uses True, False, and None to represent TRUE, FALSE, and NULL in the database.[2] That's why values passed to filter on a BooleanField are cast to bool.

While allowing some slop might be considered more "Pythonic" is some cases, I feel "explicit is better then implicit" in this case given that SQL doesn't allow boolean columns to be set in an implicit "Pythonic" truth-y/false-y way.


[1](http://www.postgresql.org/docs/9.1/static/datatype-boolean.html)

Anssi Kääriäinen

unread,
Feb 4, 2016, 1:25:50 AM2/4/16
to django-d...@googlegroups.com
I'm with Tim here - we shouldn't alter the behavior at this point.
> https://groups.google.com/d/msgid/django-developers/fbad2b08-6593-4488-93ea-8a466f1f3fdd%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages