From 16fe73d918c8a35f7122aed858312bd3163ac454 Mon Sep 17 00:00:00 2001
From: Joseph Kocherhans <joseph@jkocherhans.com>
Date: Wed, 24 Feb 2010 17:36:18 +0000
Subject: [PATCH] Fixed #7190. Boolean fields now return bool values instead of
 1 or 0. Thanks, Alex Gaynor.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12578 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 django/db/models/fields/__init__.py         | 25 +++++++++++++++------
 docs/ref/databases.txt                      | 11 +++++----
 docs/ref/models/fields.txt                  | 15 ++++---------
 docs/releases/1.2.txt                       | 10 +++++++++
 tests/regressiontests/model_fields/tests.py | 10 +++++++++
 5 files changed, 47 insertions(+), 24 deletions(-)

diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index 05f16db9fe..02c69c272e 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -524,9 +524,14 @@ class BooleanField(Field):
         return "BooleanField"
 
     def to_python(self, value):
-        if value in (True, False): return value
-        if value in ('t', 'True', '1'): return True
-        if value in ('f', 'False', '0'): return False
+        if value in (True, False):
+            # if value is 1 or 0 than it's equal to True or False, but we want
+            # to return a true bool for semantic reasons.
+            return bool(value)
+        if value in ('t', 'True', '1'):
+            return True
+        if value in ('f', 'False', '0'):
+            return False
         raise exceptions.ValidationError(self.error_messages['invalid'])
 
     def get_prep_lookup(self, lookup_type, value):
@@ -934,10 +939,16 @@ class NullBooleanField(Field):
         return "NullBooleanField"
 
     def to_python(self, value):
-        if value in (None, True, False): return value
-        if value in ('None',): return None
-        if value in ('t', 'True', '1'): return True
-        if value in ('f', 'False', '0'): return False
+        if value is None:
+            return None
+        if value in (True, False):
+            return bool(value)
+        if value in ('None',):
+            return None
+        if value in ('t', 'True', '1'):
+            return True
+        if value in ('f', 'False', '0'):
+            return False
         raise exceptions.ValidationError(self.error_messages['invalid'])
 
     def get_prep_lookup(self, lookup_type, value):
diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt
index afead83d4d..3a7c3eaaca 100644
--- a/docs/ref/databases.txt
+++ b/docs/ref/databases.txt
@@ -326,12 +326,11 @@ Notes on specific fields
 Boolean fields
 ~~~~~~~~~~~~~~
 
-Since MySQL doesn't have a direct ``BOOLEAN`` column type, Django uses a
-``TINYINT`` column with values of ``1`` and ``0`` to store values for the
-:class:`~django.db.models.BooleanField` model field. Refer to the documentation
-of that field for more details, but usually this won't be something that will
-matter unless you're printing out the field values and are expecting to see
-``True`` and ``False.``.
+.. versionchanged:: 1.2
+
+In previous versions of Django when running under MySQL ``BooleanFields`` would
+return their data as ``ints``, instead of true ``bools``.  See the release
+notes for a complete description of the change.
 
 Character fields
 ~~~~~~~~~~~~~~~~
diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
index cd66c468dc..d53bef2acf 100644
--- a/docs/ref/models/fields.txt
+++ b/docs/ref/models/fields.txt
@@ -342,18 +342,11 @@ A true/false field.
 
 The admin represents this as a checkbox.
 
-.. admonition:: MySQL users..
+.. versionchanged:: 1.2
 
-    A boolean field in MySQL is stored as a ``TINYINT`` column with a value of
-    either 0 or 1 (most databases have a proper ``BOOLEAN`` type instead). So,
-    for MySQL, only, when a ``BooleanField`` is retrieved from the database
-    and stored on a model attribute, it will have the values 1 or 0, rather
-    than ``True`` or ``False``. Normally, this shouldn't be a problem, since
-    Python guarantees that ``1 == True`` and ``0 == False`` are both true.
-    Just be careful if you're writing something like ``obj is True`` when
-    ``obj`` is a value from a boolean attribute on a model. If that model was
-    constructed using the ``mysql`` backend, the "``is``" test will fail.
-    Prefer an equality test (using "``==``") in cases like this.
+    In previous versions of Django when running under MySQL ``BooleanFields``
+    would return their data as ``ints``, instead of true ``bools``.  See the
+    release notes for a complete description of the change.
 
 ``CharField``
 -------------
diff --git a/docs/releases/1.2.txt b/docs/releases/1.2.txt
index b952ec1f6c..703ded3437 100644
--- a/docs/releases/1.2.txt
+++ b/docs/releases/1.2.txt
@@ -302,6 +302,16 @@ created using ``decorator_from_middleware``.
 
 .. _deprecated-features-1.2:
 
+``BooleanField`` on MySQL
+--------------------------
+
+In previous versions of Django ``BoleanFields`` under MySQL would return their
+values as either ``1`` or ``0``, instead of ``True`` or ``False``.  For most
+people this shouldn't have been a problem because ``bool`` is a subclass of
+``int``, however in Django 1.2 MySQL correctly returns a real ``bool``.  The
+only time this should ever be an issue is if you were expecting printing the
+``repr`` of a ``BooleanField`` to print ``1`` or ``0``.
+
 Features deprecated in 1.2
 ==========================
 
diff --git a/tests/regressiontests/model_fields/tests.py b/tests/regressiontests/model_fields/tests.py
index 18bfbd37ee..2ac0af3267 100644
--- a/tests/regressiontests/model_fields/tests.py
+++ b/tests/regressiontests/model_fields/tests.py
@@ -108,12 +108,22 @@ class BooleanFieldTests(unittest.TestCase):
         self.assertEqual(f.get_db_prep_lookup('exact', 0, connection=connection), [False])
         self.assertEqual(f.get_db_prep_lookup('exact', None, connection=connection), [None])
 
+    def _test_to_python(self, f):
+        self.assertTrue(f.to_python(1) is True)
+        self.assertTrue(f.to_python(0) is False)
+
     def test_booleanfield_get_db_prep_lookup(self):
         self._test_get_db_prep_lookup(models.BooleanField())
 
     def test_nullbooleanfield_get_db_prep_lookup(self):
         self._test_get_db_prep_lookup(models.NullBooleanField())
 
+    def test_booleanfield_to_python(self):
+        self._test_to_python(models.BooleanField())
+
+    def test_nullbooleanfield_to_python(self):
+        self._test_to_python(models.NullBooleanField())
+
     def test_booleanfield_choices_blank(self):
         """
         Test that BooleanField with choices and defaults doesn't generate a