【问题标题】:Django Rest Framework custom ListSerializer only returning dictionary keys, not valuesDjango Rest Framework 自定义 ListSerializer 只返回字典键,而不是值
【发布时间】:2018-05-04 00:16:19
【问题描述】:

我正在使用自定义 ListSerializer 重新格式化 JSON 响应,当我从序列化器内部登录时它会生成正确的格式,但是当它返回到 ViewSet 时,响应变成字典键列表而不是包含包含键和值的整个字典。

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

views.py

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)

serializers.py

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 的新手;我可能根本不明白它们是如何工作的,但这种行为对我来说确实是出乎意料的。

【问题讨论】:

  • ListSerializer 可能将其数据视为可迭代的,并且迭代 dict 会产生其键。
  • ListSerializer 不应该是实际序列化数据的对象,这就是 ElementSerializer 的用途。 ListSerializer 允许您在创建或更新对象时自定义行为。 django-rest-framework.org/api-guide/serializers/#listserializer
  • 谢谢@themanatuf;您的回复使我重新构建了我的代码,以便我不使用ListSerializer,而是在视图后序列化中重新格式化 JSON 响应。查看相关问题:stackoverflow.com/questions/47370007/…

标签: python json django django-rest-framework


【解决方案1】:

根据文档定义: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

【讨论】:

    【解决方案2】:

    问题出在 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
    

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

    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'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-12
      • 2019-05-09
      • 1970-01-01
      • 2019-02-02
      • 1970-01-01
      相关资源
      最近更新 更多