【问题标题】:Django Rest Framework to return dicts instead of OrderedDictsDjango Rest 框架返回字典而不是 OrderedDicts
【发布时间】:2018-06-22 19:30:28
【问题描述】:

我有一个带有两个附加 SerializerMethodField 字段的序列化程序:

class BentoSerializer(ModelSerializer):
    zones = SerializerMethodField()
    lead_zone = SerializerMethodField()

    def get_zones(self, obj):
        zone_queryset = obj.get_zones()
        return ZoneSerializer(zone_queryset, many=True).data

    def get_lead_zone(self, obj):
        zone_queryset = obj.get_lead_zone()
        return ZoneSerializer(zone_queryset).data

    class Meta:
        model = Bento
        fields = ('lead_zone', 'zones', )

我需要从序列化器出来的数据是嵌套的 JSON(ZoneSerializer 包含类似的 SerializerMethodFields,以及普通的模型字段),但它以 OrderedDict 的形式出现。

有没有办法配置序列化器,使BentoSerializer(obj).data 返回嵌套的 JSON,我应该递归地将 OrderedDicts 转换为 dicts,还是有一些我不知道的其他序列化器方法来获取非有序数据?

非常感谢!

PS:当前来自通过序列化器发送的工厂对象的示例数据:

[OrderedDict([('order', 1), ('columns', [OrderedDict([('order', 1), ('blocks', [OrderedDict([('order', 1), ('block_type', 'Text'), ('blockcontent', 'Cum inventore sed fugit aliquam doloribus. Alias exercitationem odit asperiores rerum qui aperiam cum fugit.'), ('heading', 'Adipisci possimus dolore assumenda sapiente velit amet odio doloremque.')])]), ('sticky', False), ('weight', 12), ('is_slideshow', False)])]), ('has_background_image', False), ('is_lead', False), ('is_slideshow', False), ('background_image', None), ('background_treatment', 'dark')])]
<class 'rest_framework.utils.serializer_helpers.ReturnList'>
{'lead_zone': {'background_image': None,
               'background_treatment': 'dark',
               'columns': [OrderedDict([('order', 1), ('blocks', [OrderedDict([('order', 1), ('block_type', 'Image'), ('blockcontent', '/media/media/2018/06/22/adatestfile_SfZMYPw.png'), ('heading', 'Reprehenderit officiis aliquid inventore enim quibusdam inventore beatae.')])]), ('sticky', False), ('weight', 12), ('is_slideshow', False)])],
               'has_background_image': False,
               'is_lead': True,
               'is_slideshow': False,
               'order': 1},
 'zones': [OrderedDict([('order', 1), ('columns', [OrderedDict([('order', 1), ('blocks', [OrderedDict([('order', 1), ('block_type', 'Text'), ('blockcontent', 'Cum inventore sed fugit aliquam doloribus. Alias exercitationem odit asperiores rerum qui aperiam cum fugit.'), ('heading', 'Adipisci possimus dolore assumenda sapiente velit amet odio doloremque.')])]), ('sticky', False), ('weight', 12), ('is_slideshow', False)])]), ('has_background_image', False), ('is_lead', False), ('is_slideshow', False), ('background_image', None), ('background_treatment', 'dark')])]}

【问题讨论】:

  • 你的标题和问题矛盾!

标签: python django serialization django-rest-framework


【解决方案1】:

类/模型通过此导入from rest_framework.response import Response 与 Django Rest 框架视图结合,被序列化为一个 OrderedDict 类型,以供Response 方法使用。它通常会以内容类型返回数据,该内容类型要么在运行时通过DEFAULT_RENDERER_CLASSES 项目设置分配,通过初始化时传递的序列化程序属性分配,要么由请求期间发送的Accept 标头确定.详细信息可以在 http://www.django-rest-framework.org/api-guide/renderers/ 的 DRF 文档中找到。

因此,调用 Response(BentoSerializer(obj).data) 在通过 APIView 等视图或 ModelViewSet 上的路由传递时应将 JSON 格式的数据返回给客户端。

但是,您也可以只使用import json 并调用json.dumps(BentoSerializer(obj).data),然后将输出所需的 JSON。我在 django shell 中使用自己的序列化程序对此进行了测试。

编辑

请注意,您不能简单地转储日期时间...您最终可能不得不编写一个补丁来将日期时间和日期对象转换为您期望的格式。

例如。

def json_dt_patch(o):
    import datetime
    from decimal import Decimal

    if isinstance(o, datetime.date) or isinstance(o, datetime.datetime):
        return o.strftime("%Y/%m/%d %H:%M:%S")
    elif isinstance(o, Decimal):
        return str(o)
    return o

import json

json.dumps(data, default=json_dt_patch)

【讨论】:

  • 感谢您更清楚地了解序列化程序如何融入 DRF 工作流程,以及仅转储 JSON 的提示!
  • json.dumps(data['attributes']) 对我不起作用。我收到错误“QuerySet 类型的对象不是 JSON 可序列化的”。我相信这是指包含每个属性的列表。
  • attributes 是一个相关的查询集字段。您需要先对其进行序列化。例如。 json.dumps(AttributeSerializer(data["attributes"], many=True).data)
【解决方案2】:

从序列化验证器获取 Ordered Dict 时,您可以轻松地将其转换为完整形式的 Dict,例如 JSONRenderer。这通常在嵌套的序列化程序中返回。

    serializer = XXXSerializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    payload = loads(dumps(serializer.data))
    print(payload)

来自

{'connection_alias': 'dev', 'payment_gateway_type': 'Stripe', 'restaurant_id': 'STRIPE_SANDBOX_TEST', 'card_info': OrderedDict([('card_type', 'VISA'), ('card_number', 'xxxxx'), ('card_expiry_month', 'xx'), ('card_expiry_year', 'xx'), ('card_cvc', 'xxx'), ('cardholder_name', 'xxxxxx')])

{'connection_alias': 'dev', 'payment_gateway_type': 'Stripe', 'restaurant_id': 'STRIPE_SANDBOX_TEST', 'card_info': {'card_type': 'VISA', 'card_number': 'xxxxxxxxx', 'card_expiry_month': 'xx', 'card_expiry_year': 'xx', 'card_cvc': 'xxx', 'cardholder_name': 'xxxxxx'}}

【讨论】:

    【解决方案3】:

    这是@NicholasClaudeLeBlanc 答案的附录。

    我无法让 json.dumps 在我的上下文中工作。 django-rest-framework 使用的实际 JSON 渲染器可以这样获取:

    from rest_framework.renderers import JSONRenderer
    renderer = JSONRenderer()
    renderer.render
    

    renderer's documentation

    【讨论】:

      【解决方案4】:

      你可以使用:

      class BentoSerializer(ModelSerializer):
          zones = SerializerMethodField()
          lead_zone = SerializerMethodField()
      
          def get_zones(self, obj):
              zone_data = ZoneSerializer(obj.zones, many=True)
              data_list = []
              for i in zone_data.data:
                  data_list.append(dict(i))
              return data_list
      
          def get_lead_zone(self, obj):
      
              lead_zone_data = ZoneSerializer(obj.lead_zone, many=True)
              data_list = []
              for i in lead_zone_data.data:
                  data_list.append(dict(i))
              return data_list
      
          class Meta:
              model = Bento
              fields = ('lead_zone', 'zones', )
      

      【讨论】:

        猜你喜欢
        • 2017-08-21
        • 2018-05-22
        • 1970-01-01
        • 2019-11-10
        • 2018-05-04
        • 1970-01-01
        • 2014-10-16
        • 2017-12-27
        • 2017-02-09
        相关资源
        最近更新 更多