[Django]-Django REST Framework: how to substitute null with empty string?

8👍

You could use a SerializerMethodField.

class AttendanceSerializer(serializers.ModelSerializer):

    face_image = serializers.SerializerMethodField()

    class Meta: 
        model = Attendance
        fields = ('id', 'face_image')

    def get_face_image(self, instance):
        return (instance.face_image.url if instance.face_image else '')
👤AKX

30👍

Override the to_representation() method of AttendanceSerializer as,

class AttendanceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Attendance
        fields = ('id', 'face_image')

    def to_representation(self, instance):
        data = super().to_representation(instance)
        if not data['face_image']:
            data['face_image'] = ""
        return data

UPDATE (11/03/2019)

I have lots of fields and its not really good idea that I repeat this code for all of them, isn’t there a better way to do it for all fields?

class AttendanceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Attendance
        fields = ('id', 'face_image')

    def to_representation(self, instance):
        my_fields = {'field_1', 'field_2', 'field_3', 'field_4', 'field_5'}
        data = super().to_representation(instance)
        for field in my_fields:
            try:
                if not data[field]:
                    data[field] = ""
            except KeyError:
                pass
        return data
👤JPG

6👍

Code for iteration over all fields mentioned in the Serializer Meta:

def to_representation(self, instance):
    data = super().to_representation(instance)
    for key, value in data.items():
        try:
            if not value:
                data[key] = ""
        except KeyError:
            pass
    return data

5👍

To add to JPG’s answer, here is a mixin that allows re-using the logic of overriding the to_representation method more easily. It also ensures that the values are None not just falsy.

class ConvertNoneToStringSerializerMixin():
    """
    Mixin to convert None to empty strings.

    This must be added as the first inherited class. The property `Meta.none_to_str_fields` must
    be defined in order for this to have any effect. This only applies to representations,
    when we export our instance data, not when we acquire and validate data.
    """
    def get_none_to_str_fields(self):
        meta = getattr(self, 'Meta', None)
        return getattr(meta, 'none_to_str_fields', [])

    def to_representation(self, instance):
        fields = self.get_none_to_str_fields()
        data = super().to_representation(instance)

        if not fields or not isinstance(data, dict):
            return data

        for field in fields:
            if field in data and data[field] is None:
                data[field] = ''
        return data

This is how you would use it:

class AttendanceSerializer(ConvertNoneToStringSerializerMixin, serializers.ModelSerializer):
    class Meta:
        model = Attendance
        fields = ('id', 'face_image')
        none_to_str_fields = ('face_image', )

Also, for those who were wondering, we cannot override the to_representation method of a Field itself because the core implementation of Serializer will skip calling to_representation from the field when the value is None. Therefore overriding the serializer is the only way this can be achieved.

👤FMCorz

0👍

You can custumize a serializer field and use it as the default ModelSerializer field mapping for ImageField.

Note: The following code snippet should be loaded before you serializer class.

from rest_framework import serializers
from django.db import models


class MyImageField(serializers.ImageField):
    def __init__(self, *args, **kwargs):
        self.null_as_blank = kwargs.pop('null_as_blank', True)
        if self.null_as_blank:
            kwargs['allow_blank'] = True
        super().__init__(*args, **kwargs)

    def to_internal_value(self, data):
        value = super().to_internal_value(data)
        # Handle deserializer, change blank value back to null.
        if self.null_as_blank and value == '':
            value = None
        return value

    def to_representation(self, value):
        value = super().to_internal_value(value)
        if self.null_as_blank and value is None:
            value = ''
        return value


serializers.ModelSerializer.serializer_field_mapping[models.ImageField] = MyImageField

Leave a comment