diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 05f16db9fee..02c69c272e8 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 afead83d4d1..3a7c3eaaca2 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 cd66c468dc2..d53bef2acf3 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 b952ec1f6c7..703ded34378 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 18bfbd37eed..2ac0af32675 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