[Django]-Django rest framework Serializer validate field data type

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
        )
πŸ‘€Alex Lisovoy

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)
πŸ‘€Geotob

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.

πŸ‘€user1635536

Leave a comment