Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding Django-Rest-Framework serializer is_valid method

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
like image 218
Diesel Avatar asked Jul 08 '15 01:07

Diesel


People also ask

What is serializer Is_valid?

is_valid perform validation of input data and confirm that this data contain all required fields and all fields have correct types. If validation process succeded is_valid set validated_data dictionary which is used for creation or updating data in DB.

Do we need Serializers in Django REST Framework?

Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.

How do I pass Queryset to serializer?

To serialize a queryset or list of objects instead of a single object instance, you should pass the many=True flag when instantiating the serializer. You can then pass a queryset or list of objects to be serialized.

What is difference between ModelSerializer and serializer?

The ModelSerializer class is the same as a regular Serializer class, except that: It will automatically generate a set of fields for you, based on the model. It will automatically generate validators for the serializer, such as unique_together validators. It includes simple default implementations of .


1 Answers

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)
like image 128
Mark Galloway Avatar answered Nov 15 '22 05:11

Mark Galloway