django-rest-framework

DRF serializer accepts an int value for a serializer charfield instead of rasing an error for a miss matched value


good people of Django,

I was exploring DRF and made a simple CRUD API, everything was smooth and working as expected, nothing special here.

But, when I was trying to test how DRF will handle the different cases of missing or wrong values in a POST request I got something that was actually very odd to me.

Let's take this snippet as an example for the body of POST request data:

{
    "title": "It doesn't matter",
    "description": "A short one because life is fast",
    "body": "Test test test test"
}

As you can see, all values are string.

So, I replaced a string value with an int value instead ( like 96, not "96" for sure ) and surprisingly the POST request was successful!

The serializer converted the int value on its own to a string and accepted the request, it didn't raise an error or anything, so is there a reasonable explanation why happened at first place rather than raising an error for unexpected value?


Solution

  • It is how DRF was designed:

    def to_internal_value(self, data):
        # We're lenient with allowing basic numerics to be coerced into strings,
        # but other types should fail. Eg. unclear if booleans should represent as `true` or `True`,
        # and composites such as lists are likely user error.
        if isinstance(data, bool) or not isinstance(data, (str, int, float,)):
            self.fail('invalid')
        value = str(data)
        return value.strip() if self.trim_whitespace else value
    

    It is CharField method, here: https://github.com/encode/django-rest-framework/blob/master/rest_framework/fields.py#L798

    Case is that in this direction - it is no issue; As you sometimes want to save numeric values as text, eg. TAX IDENTIFICATION NUMBERS (TIN), etc. And being strict here can cause more harm than good.

    Eg. IntegerField - has no this behavior it will do very strict checking if the value is an integer.