Django

Code

Ticket #7190 (closed: fixed)

Opened 2 years ago

Last modified 3 weeks ago

BooleanField does not return <type: 'bool'>

Reported by: Jeffrey Froman Assigned to: nobody
Milestone: 1.2 Component: Database layer (models, ORM)
Version: SVN Keywords: BooleanField, type
Cc: leosoto Triage Stage: Accepted
Has patch: 1 Needs documentation: 1
Needs tests: 0 Patch needs improvement: 0

Description (Last modified by ramiro)

In some cases, a BooleanField returns an integer instead of a bool. The following example uses a MySQL backend:

# models.py
from django.db import models

class Simple(models.Model):
    b = models.!BooleanField()

$ ./manage.py syncdb
Creating table djest_simple
$ python
Python 2.5 (r25:51908, Sep 10 2007, 13:30:49)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from djest.models import Simple
>>> simple = Simple.objects.create(b=True)
>>> simple.b
True
>>> simple_2 = Simple.objects.get(pk=simple.pk)
>>> simple_2.b
1

This may not be a problem for normal usage, but makes testing, particularly using doctest, much less elegant.

Attachments

boolfield.diff (0.9 kB) - added by Jeffrey Froman <django.tcijf@olympus.net> on 05/07/08 18:15:14.
patch for django/db/models/fields/init.py
mysql.patch (1.2 kB) - added by pim on 06/19/08 10:40:15.
django-real-bools.diff (2.9 kB) - added by Alex on 02/24/10 10:13:14.
django-real-bools.2.diff (4.4 kB) - added by Alex on 02/24/10 11:15:00.
django-real-bools.3.diff (5.5 kB) - added by Alex on 02/24/10 11:17:31.
django-real-bools.4.diff (5.9 kB) - added by Alex on 02/24/10 11:22:50.

Change History

05/07/08 18:15:14 changed by Jeffrey Froman <django.tcijf@olympus.net>

  • attachment boolfield.diff added.

patch for django/db/models/fields/init.py

(follow-ups: ↓ 5 ↓ 7 ) 05/07/08 19:15:14 changed by ubernostrum

  • needs_better_patch changed.
  • needs_tests changed.
  • needs_docs changed.

This is kind of tricky, because under the hood in Python bool is a subclass of int that only ever has two instances (which test equal to 0 and 1 for False and True, respectively). Not all DBs actually store a boolean value, either; some store a 0 or a 1, and return that. Given that, and Python's general bent toward duck typing, I'm not sure whether we should strictly ensure that it always returns a bool instance.

06/16/08 11:18:35 changed by ramiro

  • description changed.

06/19/08 10:40:15 changed by pim

  • attachment mysql.patch added.

06/20/08 08:31:26 changed by glassfordm

Note: the approach in the mysql.patch attachment handles some cases that the approach in the boolfield.diff attachment does not: for example, the former fixes results returned by calling Model.objects.value(), and so fixes the doctests in django/tests/regressiontests/model_inheritance_regress/models.py; the latter does not fix these doctests.

Also, a note from the django developer's mailing list:

Pim Van Heuven wrote:

The lack of boolean type coercion is more serious than it looks like at first glance. (starting from the example at http://code.djangoproject.com/ticket/7190) In [1]: import django.newforms as forms In [2]: from django.newforms.models import model_to_dict In [3]: from simple.models import Simple In [4]: simple_false = Simple.objects.create(b=False) In [5]: simple_false_2 = Simple.objects.get(pk=simple_false.pk) In [6]: class SimpleForm?(forms.ModelForm?): ...: b = forms.BooleanField?(widget=forms.HiddenInput?) ...: class Meta: ...: model = Simple ...: In [7]: SimpleForm?(data = model_to_dict(simple_false)).as_p() Out[7]: u'<input type="hidden" name="b" value="False" id="id_b" />' In [8]: SimpleForm?(data = model_to_dict(simple_false_2)).as_p() Out[8]: u'<input type="hidden" name="b" value="0" id="id_b" />' When you POST the Out[8] form the value becomes bool("0") = True. So when you save simple_false_2 based on the form the value is inverted from False to True. Seems like a critical error... The mysql.patch solves this issue too. Pim.

06/25/08 13:42:18 changed by leosoto

  • cc set to leosoto.

(in reply to: ↑ 1 ) 06/26/08 14:29:22 changed by anonymous

Replying to ubernostrum:

This is kind of tricky, because under the hood in Python bool is a subclass of int that only ever has two instances (which test equal to 0 and 1 for False and True, respectively). Not all DBs actually store a boolean value, either; some store a 0 or a 1, and return that. Given that, and Python's general bent toward duck typing, I'm not sure whether we should strictly ensure that it always returns a bool instance.

I dont think we can get away with duck typing here since it causes problems with the tests, Model.objects.value() and when posting a form with a hidden input for a boolean field (see example below). After a quick grep it seems that the old mysql, sqlite and the oracle driver all have some kind of boolean type coercion. Besides the mysql.path confines the changes to the mysql backend.

07/29/08 12:49:25 changed by Paul Kenjora

I applied the patch to 0.97-pre-SVN-5 with no effect. Please advise if anyone else has applied the patch with success, maybe missing some code on the attachments?

(in reply to: ↑ 1 ; follow-up: ↓ 8 ) 08/08/08 05:46:51 changed by bear330

Replying to ubernostrum:

This is kind of tricky, because under the hood in Python bool is a subclass of int that only ever has two instances (which test equal to 0 and 1 for False and True, respectively). Not all DBs actually store a boolean value, either; some store a 0 or a 1, and return that. Given that, and Python's general bent toward duck typing, I'm not sure whether we should strictly ensure that it always returns a bool instance.

Yes, 1 means true in python, but not at this situation:

>>> 1 is True
False

I also encounter this problem in my code. I think it should alway return True or False for Boolean field. If I use:

if field is True

that will fail. but if I use:

if field

That will be true if field is any non false value. (list, tuple, string...)

To make BooleanField? always return True or False, it only need to modify BooleanField?'s to_python method.

Thanks.

(in reply to: ↑ 7 ) 08/08/08 05:51:22 changed by bear330

Replying to bear330:

To make BooleanField? always return True or False, it only need to modify BooleanField?'s to_python method.

if value in (True, False): return value

=>

if value in (True, False): return value == True

Thanks.

08/08/08 14:19:10 changed by ericholscher

  • stage changed from Unreviewed to Design decision needed.
  • milestone set to 1.0 maybe.

08/22/08 18:57:21 changed by jacob

  • status changed from new to closed.
  • resolution set to wontfix.

This basically comes down to a limitation of MySQL and MySQLdb. The cast function technically would work, but it's silly to cast any tinyint to bool.

08/22/08 20:10:47 changed by

  • milestone deleted.

Milestone 1.0 maybe deleted

09/02/08 09:03:27 changed by stengleind

  • status changed from closed to reopened.
  • needs_docs set to 1.
  • resolution deleted.

By the way, this killed some code of mine that depended on True being True. My functional test had an assertEqual(True, someBooleanField) and it silently broke when I switched backends from sqlite to MySQL.

If it is not going to be fixed, it needs to be very clearly documented (which it is currently not).

-Dave

09/02/08 10:03:03 changed by jacob

  • status changed from reopened to closed.
  • resolution set to wontfix.

Please don't reopen tickets closed by a core developer, and especially not if you're going to change the subject. If you disagree with the wontfix call, bring it up on django-dev; if you'd like something else done (more docs are almost always a good idea), open a new ticket.

09/02/08 12:56:52 changed by stengleind

Ticket done (http://code.djangoproject.com/ticket/8802).

I will bring this up on the mailing list because:

1 == True True

1 is True False

-Dave

03/04/09 13:29:58 changed by to.roma.from.djbug@qwertty.com

Could you please elaborate what exactly prevents you from applying one of the patches? I searched the mailing list archives and the only obstacle I found was inconsistency with qs.values() which would return 0/1 rather than True/False, but to my mind it’s values()’s behavior that should be changed, not the other way round (#10412). You call the int->bool cast “silly”, and maybe it is, but what are your actual concerns—performance hit, inconsistency, something else?

01/26/10 19:03:09 changed by ubernostrum

  • status changed from closed to reopened.
  • stage changed from Design decision needed to Accepted.
  • resolution deleted.
  • milestone set to 1.2.

Reopening after discussion in #django-dev, targeting for 1.2.

Note that the eventual fix for this can't be backported into 1.1 since we documented the behavior.

02/24/10 10:13:14 changed by Alex

  • attachment django-real-bools.diff added.

02/24/10 11:15:00 changed by Alex

  • attachment django-real-bools.2.diff added.

02/24/10 11:17:31 changed by Alex

  • attachment django-real-bools.3.diff added.

02/24/10 11:22:50 changed by Alex

  • attachment django-real-bools.4.diff added.

02/24/10 11:36:19 changed by jkocherhans

  • status changed from reopened to closed.
  • resolution set to fixed.

(In [12578]) Fixed #7190. Boolean fields now return bool values instead of 1 or 0. Thanks, Alex Gaynor.


Add/Change #7190 (BooleanField does not return <type: 'bool'>)




Change Properties
Action