[Django]-Remove null fields from Django Rest Framework response

37๐Ÿ‘

โœ…

I found this solution to be the simplest.

from collections import OrderedDict
from rest_framework import serializers

class NonNullModelSerializer(serializers.ModelSerializer):
    def to_representation(self, instance):
        result = super(NonNullModelSerializer, self).to_representation(instance)
        return OrderedDict([(key, result[key]) for key in result if result[key] is not None])
๐Ÿ‘คSimon

20๐Ÿ‘

I faced a similar problem and solved it as follows:

from operator import itemgetter


class MetaTagsSerializer(serializers.ModelSerializer):
    class Meta:
        model = MetaTags

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        # Here we filter the null values and creates a new dictionary
        # We use OrderedDict like in original method
        ret = OrderedDict(filter(itemgetter(1), ret.items()))
        return ret

Or if you want to filter only empty fields you can replace the itemgetter(1) by the following:

lambda x: x[1] is not None
๐Ÿ‘คasduj

18๐Ÿ‘

The answer from CubeRZ didnโ€™t work for me, using DRF 3.0.5. I think the method to_native has been removed and is now replaced by to_representation, defined in Serializer instead of BaseSerializer.

I used the class below with DRF 3.0.5, which is a copy of the method from Serializer with a slight modification.

from collections import OrderedDict

from rest_framework import serializers
from rest_framework.fields import SkipField

class NonNullSerializer(serializers.ModelSerializer):

    def to_representation(self, instance):
        """
        Object instance -> Dict of primitive datatypes.
        """
        ret = OrderedDict()
        fields = [field for field in self.fields.values() if not field.write_only]

        for field in fields:
            try:
                attribute = field.get_attribute(instance)
            except SkipField:
                continue

            if attribute is not None:
                represenation = field.to_representation(attribute)
                if represenation is None:
                    # Do not seralize empty objects
                    continue
                if isinstance(represenation, list) and not represenation:
                   # Do not serialize empty lists
                   continue
                ret[field.field_name] = represenation

        return ret

EDIT incorporated code from comments

๐Ÿ‘คDavid R.

10๐Ÿ‘

You could try overriding the to_native function:

class MetaTagsSerializer(serializers.ModelSerializer):
    class Meta:
        model = MetaTags

    def to_native(self, obj):
        """
        Serialize objects -> primitives.
        """
        ret = self._dict_class()
        ret.fields = self._dict_class()

        for field_name, field in self.fields.items():
            if field.read_only and obj is None:
                continue
            field.initialize(parent=self, field_name=field_name)
            key = self.get_field_key(field_name)
            value = field.field_to_native(obj, field_name)

            # Continue if value is None so that it does not get serialized.
            if value is None:
                continue

            method = getattr(self, 'transform_%s' % field_name, None)
            if callable(method):
                value = method(obj, value)
            if not getattr(field, 'write_only', False):
                ret[key] = value
            ret.fields[key] = self.augment_field(field, field_name, key, value)

        return ret

I basically copied the base to_native function from serializers.BaseSerializer and added a check for the value.

UPDATE:
As for DRF 3.0, to_native() was renamed to to_representation() and its implementation was changed a little. Hereโ€™s the code for DRF 3.0 which ignores null and empty string values:

def to_representation(self, instance):
    """
    Object instance -> Dict of primitive datatypes.
    """
    ret = OrderedDict()
    fields = self._readable_fields

    for field in fields:
        try:
            attribute = field.get_attribute(instance)
        except SkipField:
            continue

        # KEY IS HERE:
        if attribute in [None, '']:
            continue

        # We skip `to_representation` for `None` values so that fields do
        # not have to explicitly deal with that case.
        #
        # For related fields with `use_pk_only_optimization` we need to
        # resolve the pk value.
        check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
        if check_for_none is None:
            ret[field.field_name] = None
        else:
            ret[field.field_name] = field.to_representation(attribute)

    return ret
๐Ÿ‘คCubeRZ

0๐Ÿ‘

Two Options are added with:

  • Remove key having value None
  • Remove key having value None or Blank.
from collections import OrderedDict
from rest_framework import serializers


# None field will be removed
class NonNullModelSerializer(serializers.ModelSerializer):
    def to_representation(self, instance):
        result = super(NonNullModelSerializer, self).to_representation(instance)
        return OrderedDict([(key, result[key]) for key in result if result[key] is not None])


# None & Blank field will be removed
class ValueBasedModelSerializer(serializers.ModelSerializer):
    def to_representation(self, instance):
        result = super(ValueBasedModelSerializer, self).to_representation(instance)
        return OrderedDict([(key, result[key]) for key in result if result[key] ])

Simply modification for none & blank value based key removal, for my
use. Thanks goes to @Simon.

๐Ÿ‘คChandan Sharma

Leave a comment