Allow nullable BooleanField in Django 2.1 (#6183)

* Add tests for BooleanField when nullable

* Allow nullable BooleanField in Django 2.1

* Drop 'BooleanField.allow_null' check

* Remove conflicting false/null values
This commit is contained in:
Ryan P Kilby 2018-09-13 09:25:03 -07:00 committed by Tom Christie
parent 5f1f2b1003
commit fc6cbb5b26
3 changed files with 37 additions and 6 deletions

View File

@ -674,10 +674,7 @@ class BooleanField(Field):
'0', 0, 0.0, '0', 0, 0.0,
False False
} }
NULL_VALUES = {'null', 'Null', 'NULL', '', None}
def __init__(self, **kwargs):
assert 'allow_null' not in kwargs, '`allow_null` is not a valid option. Use `NullBooleanField` instead.'
super(BooleanField, self).__init__(**kwargs)
def to_internal_value(self, data): def to_internal_value(self, data):
try: try:
@ -685,6 +682,8 @@ class BooleanField(Field):
return True return True
elif data in self.FALSE_VALUES: elif data in self.FALSE_VALUES:
return False return False
elif data in self.NULL_VALUES and self.allow_null:
return None
except TypeError: # Input is an unhashable type except TypeError: # Input is an unhashable type
pass pass
self.fail('invalid', input=data) self.fail('invalid', input=data)
@ -694,6 +693,8 @@ class BooleanField(Field):
return True return True
elif value in self.FALSE_VALUES: elif value in self.FALSE_VALUES:
return False return False
if value in self.NULL_VALUES and self.allow_null:
return None
return bool(value) return bool(value)
@ -718,7 +719,7 @@ class NullBooleanField(Field):
'0', 0, 0.0, '0', 0, 0.0,
False False
} }
NULL_VALUES = {'n', 'N', 'null', 'Null', 'NULL', '', None} NULL_VALUES = {'null', 'Null', 'NULL', '', None}
def __init__(self, **kwargs): def __init__(self, **kwargs):
assert 'allow_null' not in kwargs, '`allow_null` is not a valid option.' assert 'allow_null' not in kwargs, '`allow_null` is not a valid option.'

View File

@ -657,7 +657,7 @@ class TestBooleanField(FieldValues):
class TestNullBooleanField(TestBooleanField): class TestNullBooleanField(TestBooleanField):
""" """
Valid and invalid values for `BooleanField`. Valid and invalid values for `NullBooleanField`.
""" """
valid_inputs = { valid_inputs = {
'true': True, 'true': True,
@ -682,6 +682,16 @@ class TestNullBooleanField(TestBooleanField):
field = serializers.NullBooleanField() field = serializers.NullBooleanField()
class TestNullableBooleanField(TestNullBooleanField):
"""
Valid and invalid values for `BooleanField` when `allow_null=True`.
"""
@property
def field(self):
return serializers.BooleanField(allow_null=True)
# String types... # String types...
class TestCharField(FieldValues): class TestCharField(FieldValues):

View File

@ -12,6 +12,7 @@ import decimal
import sys import sys
from collections import OrderedDict from collections import OrderedDict
import django
import pytest import pytest
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.validators import ( from django.core.validators import (
@ -220,6 +221,25 @@ class TestRegularFieldMappings(TestCase):
) )
self.assertEqual(unicode_repr(TestSerializer()), expected) self.assertEqual(unicode_repr(TestSerializer()), expected)
# merge this into test_regular_fields / RegularFieldsModel when
# Django 2.1 is the minimum supported version
@pytest.mark.skipif(django.VERSION < (2, 1), reason='Django version < 2.1')
def test_nullable_boolean_field(self):
class NullableBooleanModel(models.Model):
field = models.BooleanField(null=True, default=False)
class NullableBooleanSerializer(serializers.ModelSerializer):
class Meta:
model = NullableBooleanModel
fields = ['field']
expected = dedent("""
NullableBooleanSerializer():
field = BooleanField(allow_null=True, required=False)
""")
self.assertEqual(unicode_repr(NullableBooleanSerializer()), expected)
def test_method_field(self): def test_method_field(self):
""" """
Properties and methods on the model should be allowed as `Meta.fields` Properties and methods on the model should be allowed as `Meta.fields`