Overriding Django-Rest-Framework serializer is_valid method

Tags: , , ,



I have a quick question about overriding is_valid. Self is a rest_framework.serializers.ModelSerializer. I’m trying to figure out if there is a better way to modify internal data than reading/writing to the data._kwargs property. I know I can get the data pre-validation via a self.get_initial() call. But I’d also like to be able to write data. The purpose here is to change Image Data, if not properly formatted, into a format our models accept so that our API is more flexible. I know there may be other ways to accomplish my goals, but my generic question is

Is there a good method to set data on a serializer before is_valid() is called?

because it applies to other cases too. Thank you!

def is_valid(self, raise_exception=True):
    imageHandler = ImageHandler()
    if "member_profile" in self._kwargs["data"]:
        if "profile_image" in self._kwargs["data"]["member_profile"]:
            self._kwargs["data"]["member_profile"]["profile_image"] = imageHandler.convertImage(
                self._kwargs["data"]["member_profile"]["profile_image"])
    else:
        self._kwargs["data"]["member_profile"] = {}
    valid = super(AuthUserModelSerializer, self).is_valid(raise_exception=raise_exception)
    return valid

Answer

Personally, I would write a custom field for the profile_image(or extend image field) and overwrite the to_internal_value method to hold this custom logic. This will be called by during field validation. Here is a psuedo-example:

class ProfileImageField(ImageField):

    def to_internal_value(self, data):
       converted = ImageHandler().convertImage(data)
       return super(ProfileImageField,self).to_internal_value(converted)

To answer your generic question, I usually use custom to_internal_value() methods for fields and serializers to handle any discrepancies between incoming and expected data. These methods are run during validation and allow you to control the data in an obvious manner to someone reading your code in the future.

Clarification


The serializer itself has a ‘to_interval_value’ method which allows you to modify/process the data you pass to it during the serializer’s data validation (but before the data itself is validated). Modifying data at this point will also happen before field level validation. So, if you want to rename a field that is being passed to your endpoint into something you expect, or if you want to add a null value for a field that has not been passed in the data, this would be the place to do it.

class MySerializer(serializers.ModelSerializer):

    def to_internal_value(self, data):
       if 'member_profile' not in data:
           data['member_profile'] = {}
       return super(MySerializer,self).to_internal_value(data)


Source: stackoverflow