6π
The answer to your question is a type conversion. DRF converts a value to boolean using the following algorithm:
if value in ('true', 't', 'True', '1'):
return True
if value in ('false', 'f', 'False', '0'):
return False
return bool(value)
As you see at the last line, DRF explicitly convert value to boolean. From shell:
>>> bool('bla')
True
So that is why your example always returns True
. To avoid this effect, you need to create a custom field and specify the necessary convert rules. For example:
from rest_framework import serializers
class StrictBooleanField(serializers.BooleanField):
def from_native(self, value):
if value in ('true', 't', 'True', '1'):
return True
if value in ('false', 'f', 'False', '0'):
return False
return None
class TestSerializer(serializers.Serializer):
test_bool = StrictBooleanField(required=True)
class Meta:
fields = ('test_bool',)
...
# tests.py
class TestSerializerTestCase(unittest.TestCase):
def test_my_test(self):
data = {'test_bool': 'bla'}
serializer = TestSerializer(data=data)
self.assertFalse(serializer.is_valid())
self.assertDictEqual(
{'test_bool': [u'This field is required.']}, serializer.errors
)
2π
For future visitors, the from_native
method has been renamed in DRF >= 3.0. From changelog:
The from_native(self, value) and to_native(self, data) method names
have been replaced with the more obviously named
to_internal_value(self, data) and to_representation(self, value).
Also, instead of returning None
, you should call the fail()
method like this:
class StrictBooleanField(serializers.BooleanField):
def to_internal_value(self, value):
if value in ('true', 't', 'True', '1'):
return True
if value in ('false', 'f', 'False', '0'):
return False
self.fail('invalid', input=data)
- [Django]-Get local system time in Django
- [Django]-Load jQuery into Django
- [Django]-Backbone.js link file to model
0π
from django.core.exceptions import ValidationError
class StrictBooleanField(serializers.BooleanField):
def from_native(self, value):
if isinstance(value, str):
if value in ('true', 't', 'True', '1'):
return True
if value in ('false', 'f', 'False', '0'):
return False
if isinstance(value, bool):
return bool(value)
msg = self.error_messages['invalid']
raise ValidationError(msg)
I just change a litle the StrictBooleanField class, so that if wrong data is given for the boolean we will get invalid error for the field and not required.