[Django]-DRF – ModelSerializer with a non-model write_only field

4👍

First, you need to define this field in the serializer:

class UserSerializer(serializers.ModelSerializer):
    referrer = serializers.CharField(max_length=300, allow_blank=True)
    class Meta:
        model = User
        fields = ('id', 'first_name', 'last_name', 'referrer')
        write_only_fields = ('first_name', 'last_name', 'referrer')     #how to use this 'referrer' field to populate the Model fields?
        read_only_fields = ('id',)

(I am not really sure if you need ‘first_name’, ‘last_name’ in write_only_fields, as this means you will get only ID in response, but this depends on your requirements)

Now, you need to override the serializer restore_object method:

def restore_object(self, attrs, instance=None):
    referrer = attrs.pop('referrer')
    # parse referrer to referral_campaign, referral_media_source, inviting_user 
    ...
    instance = super(UserSerializer, self).restore_object(attrs, instance=instance)
    instance.referral_campaign = referral_campaign
    instance.referral_media_source = referral_media_source
    instance.inviting_user = inviting_user
    return instance

(This answer assumes DRF 2)

11👍

For DRF3,

class UserSerializer(serializers.ModelSerializer):
    referrer = serializers.CharField(max_length=300, allow_blank=True, write_only=True)
    
    class Meta:
        model = User
        fields = ('id', 'first_name', 'last_name', 'referrer')

    def validate(self, attrs):
        # do your stuff
        attrs.pop('referer', None)  # avoid sending it back to model creation
        return super().validate(attrs)

From this this answer

5👍

For the new comers. The ‘write_only_fields’ has been deprecated in DRF 3.

‘extra_kwargs’ is the new way. See: http://www.django-rest-framework.org/topics/3.0-announcement/#the-extra_kwargs-option

Example:

class UserSerializer(serializers.HyperlinkedModelSerializer):
    ...
    class Meta:
        model = User
        ...

        # 'write_only_fields' has been deprecated:
        #     write_only_fields = ('password',)
        extra_kwargs = {
            'password': {'write_only': True}
        }

Leave a comment