#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.