Django Rest Framework自定义ListSerializer只返回字典键,而不是值

问题描述 投票:1回答:2

我正在使用自定义ListSerializer来重新格式化JSON响应,当我从序列化程序内部进行日志记录时,它会生成正确的格式,但是当它返回到ViewSet时,响应将成为字典键的列表,而不是包含整个字典。键和值都有。

我用硬编码的JSON做了一个简化的例子来说明我认为是问题的症结所在。

views.朋友

class ElementViewSet(viewsets.ViewSet):

    ...

    @detail_route(methods=['get'])
    def elements(self, request, pk=None):
        elements = ElementFilterSet(params)
        serializer = serializers.ElementSerializer(elements, many=True)
        return Response(serializer.data)

serialize认识.朋友

class ElementListSerializer(serializers.ListSerializer):

    def to_representation(self, obj):
        result = {"home": {"label_color": "#123456","label_text": "young"},"speak": { "label_color": "","label_text": "Hello"}}
        return result


class ElementSerializer(serializers.ModelSerializer):
    class Meta:
        model = Element
        list_serializer_class = ElementListSerializer

    def to_representation(self, obj):
        result = super(ElementSerializer, self).to_representation(obj)
        return result

我得到的响应是一个字典键列表:

[
    "speak",
    "home"
]

而不是我想要的,这是整个字典(在这种情况下,只是硬编码的JSON result):

{
   "home": {
       "label_color": "#123456",
       "label_text": "young"
   },
   "speak": {
       "label_color": "",
       "label_text": "Hello"
   }
}

我是新手自定义序列化器和使用list_serializer_class;我可能只是不明白它们是如何工作的,但这种行为对我来说确实是出乎意料的。

python json django django-rest-framework
2个回答
1
投票

根据docs定义:ListSerializer类提供一次序列化和验证多个对象的行为。如果传递的数据可以表示为序列化数据,则通常不需要ListSerializers。建议的解决方案是使用嵌套的序列化程序,如果您没有从模型实例获取键值:

class ElementListSerializer(serializers.BaseSerializer):

    def to_representation(self, obj):
        return {
            'home': {"label_color": "#123456",
                     "label_text": "young"},
            'speak': {
                    "label_color": "",
                    "label_text": "Hello"}
        }

class ElementSerializer(serializers.ModelSerializer):

    element_list = ElementListSerializer() 

    class Meta:
        model = Element

    def create(self, validated_data):
        data = validated_data.pop('element_list')
        return data

0
投票

问题出在ListSerializer上的属性data中,它返回ReturnList而不是ReturnDict。

要修复代码,您必须更改data属性:

from rest_framework import serializers


class ElementListSerializer(serializers.ListSerializer):

    def to_representation(self, obj):
        result = {"home": {"label_color": "#123456","label_text": "young"},"speak": { "label_color": "","label_text": "Hello"}}
        return result

    @property
    def data(self):
        ret = serializers.BaseSerializer.data.fget(self)
        return serializers.ReturnDict(ret, serializer=self)


class ElementSerializer(serializers.ModelSerializer):
    class Meta:
        model = Element
        list_serializer_class = ElementListSerializer

    def to_representation(self, obj):
        result = super(ElementSerializer, self).to_representation(obj)
        return result

您还可以创建更通用的解决方案。它会自动将具有相同结构的dicts列表转换为一个dict,其中键将来自child's dict的指定字段。

class ListToDictSerializer(serializers.ListSerializer):
    def to_representation(self, data):
        return {
            item[self.child.Meta.dict_serializer_key]: self.child.to_representation(item)
            for item in data
        }

    @property
    def data(self):
        ret = drf_serializers.BaseSerializer.data.fget(self)
        return serializers.ReturnDict(ret, serializer=self)


class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Model
        list_serializer_class = ListToDictSerializer
        dict_serializer_key = 'id'
© www.soinside.com 2019 - 2024. All rights reserved.