#27601: BooleanField no longer accepts empty string as False value
-------------------------------------+-------------------------------------
     Reporter:  elpescado            |                    Owner:  nobody
         Type:  Bug                  |                   Status:  new
    Component:  Database layer       |                  Version:  1.10
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Changes (by Tim Graham):

 * component:  Uncategorized => Database layer (models, ORM)
 * type:  Uncategorized => Bug


Old description:

> As of 1.10, `BooleanField` no longer accepts empty string(`""` ) as False
> value. Was this change intentional? It was not mentioned in [Backwards
> incompatible changes in
> 1.10](https://docs.djangoproject.com/en/1.10/releases/1.10/#backwards-
> incompatible-1-10) section of manual.
>

> models.py:
> {{{
> class BooleanModel(models.Model):
>     value = models.BooleanField(default=False)
> }}}
>
> tests.py:
> {{{
> class BooleanFieldTest(TestCase):
>     def test_empty_string_as_value(self):
>         BooleanModel(value="").save()
> }}}
>
> Running with Django 1.9:
> {{{
>  $ python manage.py test
> Creating test database for alias 'default'...
> .
> ----------------------------------------------------------------------
> Ran 1 test in 0.001s
>
> OK
> Destroying test database for alias 'default'...
> }}}
>
> Running with Django 1.10:
> {{{
>  $ python manage.py test
> Creating test database for alias 'default'...
> E
> ======================================================================
> ERROR: test_empty_string_as_value (boolapp.tests.BooleanFieldTest)
> ----------------------------------------------------------------------
> Traceback (most recent call last):
>   File "/home/sitek/tmp/boolfield/boolapp/tests.py", line 7, in
> test_empty_string_as_value
>     BooleanModel(value="").save()
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/base.py", line 796, in save
>     force_update=force_update, update_fields=update_fields)
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/base.py", line 824, in save_base
>     updated = self._save_table(raw, cls, force_insert, force_update,
> using, update_fields)
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/base.py", line 908, in _save_table
>     result = self._do_insert(cls._base_manager, using, fields, update_pk,
> raw)
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/base.py", line 947, in _do_insert
>     using=using, raw=raw)
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/manager.py", line 85, in manager_method
>     return getattr(self.get_queryset(), name)(*args, **kwargs)
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/query.py", line 1045, in _insert
>     return query.get_compiler(using=using).execute_sql(return_id)
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/sql/compiler.py", line 1053, in execute_sql
>     for sql, params in self.as_sql():
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/sql/compiler.py", line 1006, in as_sql
>     for obj in self.query.objs
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/sql/compiler.py", line 945, in prepare_value
>     value = field.get_db_prep_save(value, connection=self.connection)
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/fields/__init__.py", line 755, in
> get_db_prep_save
>     prepared=False)
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/fields/__init__.py", line 747, in
> get_db_prep_value
>     value = self.get_prep_value(value)
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/fields/__init__.py", line 1025, in
> get_prep_value
>     return self.to_python(value)
>   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
> packages/django/db/models/fields/__init__.py", line 1018, in to_python
>     params={'value': value},
> ValidationError: [u"'' value must be either True or False."]
>
> ----------------------------------------------------------------------
> Ran 1 test in 0.004s
>
> FAILED (errors=1)
> Destroying test database for alias 'default'...
> }}}

New description:

 As of 1.10, `BooleanField` no longer accepts empty string(`""` ) as False
 value. Was this change intentional? It was not mentioned in
 [https://docs.djangoproject.com/en/1.10/releases/1.10/#backwards-
 incompatible-1-10 Backwards incompatible changes in 1.10] section of
 manual.


 models.py:
 {{{
 class BooleanModel(models.Model):
     value = models.BooleanField(default=False)
 }}}

 tests.py:
 {{{
 class BooleanFieldTest(TestCase):
     def test_empty_string_as_value(self):
         BooleanModel(value="").save()
 }}}

 Running with Django 1.9:
 {{{
  $ python manage.py test
 Creating test database for alias 'default'...
 .
 ----------------------------------------------------------------------
 Ran 1 test in 0.001s

 OK
 Destroying test database for alias 'default'...
 }}}

 Running with Django 1.10:
 {{{
  $ python manage.py test
 Creating test database for alias 'default'...
 E
 ======================================================================
 ERROR: test_empty_string_as_value (boolapp.tests.BooleanFieldTest)
 ----------------------------------------------------------------------
 Traceback (most recent call last):
   File "/home/sitek/tmp/boolfield/boolapp/tests.py", line 7, in
 test_empty_string_as_value
     BooleanModel(value="").save()
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/base.py", line 796, in save
     force_update=force_update, update_fields=update_fields)
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/base.py", line 824, in save_base
     updated = self._save_table(raw, cls, force_insert, force_update,
 using, update_fields)
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/base.py", line 908, in _save_table
     result = self._do_insert(cls._base_manager, using, fields, update_pk,
 raw)
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/base.py", line 947, in _do_insert
     using=using, raw=raw)
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/manager.py", line 85, in manager_method
     return getattr(self.get_queryset(), name)(*args, **kwargs)
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/query.py", line 1045, in _insert
     return query.get_compiler(using=using).execute_sql(return_id)
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/sql/compiler.py", line 1053, in execute_sql
     for sql, params in self.as_sql():
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/sql/compiler.py", line 1006, in as_sql
     for obj in self.query.objs
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/sql/compiler.py", line 945, in prepare_value
     value = field.get_db_prep_save(value, connection=self.connection)
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/fields/__init__.py", line 755, in
 get_db_prep_save
     prepared=False)
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/fields/__init__.py", line 747, in
 get_db_prep_value
     value = self.get_prep_value(value)
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/fields/__init__.py", line 1025, in
 get_prep_value
     return self.to_python(value)
   File "/home/sitek/.virtualenvs/teb110_sitek/local/lib/python2.7/site-
 packages/django/db/models/fields/__init__.py", line 1018, in to_python
     params={'value': value},
 ValidationError: [u"'' value must be either True or False."]

 ----------------------------------------------------------------------
 Ran 1 test in 0.004s

 FAILED (errors=1)
 Destroying test database for alias 'default'...
 }}}

--

Comment:

 The new behavior of raising a validation error to alert the developer of a
 possible misuse seems more expected to me rather than silently coercing
 any value to it's `bool` representation. If you believe the old behavior
 is better, can you provide a use case that demonstrates its merits? I'm
 not sure if it's worth documenting as that it looks more like a bug fix
 that a breakage of public API.

--
Ticket URL: <https://code.djangoproject.com/ticket/27601#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/067.82f415167bcac60400407177968dee21%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to