从Django Rest Framework响应中删除空字段

时间:2014-11-19 11:38:48

标签: python django api django-rest-framework

我使用django-rest-framework开发了一个API。 我正在使用ModelSerializer返回模型的数据。

models.py

class MetaTags(models.Model):
    title = models.CharField(_('Title'), max_length=255, blank=True, null=True)
    name = models.CharField(_('Name'), max_length=255, blank=True, null=True)

serializer.py

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

响应

{
    "meta": {
        "title": null,
        "name": "XYZ"
    }
}

理想情况下,在API响应中,不应在响应中发送任何不存在的值。 当titlenull时,我希望回复为:

{
    "meta": {
        "name": "XYZ"
    }
}

5 个答案:

答案 0 :(得分:17)

使用DRF 3.0.5,CubeRZ的答案对我不起作用。我认为方法to_native已被删除,现在被替换为在Serializer而不是BaseSerializer中定义的to_representation。

我在下面的课程中使用了DRF 3.0.5,这是一个来自Serializer的方法的副本,稍作修改。

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

编辑合并了评论中的代码

答案 1 :(得分:14)

我遇到了类似的问题并解决了如下问题:

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(list(filter(lambda x: x[1], ret.items())))
        return ret

或者,如果您只想过滤空字段,可以通过以下方法替换lambda函数:

lambda x: x[1] is not None

答案 2 :(得分:8)

我发现这个解决方案是最简单的。

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])

答案 3 :(得分:7)

您可以尝试覆盖to_native函数:

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

我基本上从serializers.BaseSerializer复制了基本的to_native函数,并添加了对值的检查。

<强>更新 至于DRF 3.0,to_native()已重命名为to_representation(),其实施方式有所改变。这是DRF 3.0的代码,它忽略空值和空字符串值:

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

答案 4 :(得分:0)

添加了两个选项:

  • 删除值为 None 的键
  • 删除值为 None 或 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] ])
<块引用>

简单地修改基于无和空白值的键删除,对于我的 采用。感谢@Simon。