如何从 rest_framework 序列化程序获得漂亮的输出

Posted

技术标签:

【中文标题】如何从 rest_framework 序列化程序获得漂亮的输出【英文标题】:How to get pretty output from rest_framework serializer 【发布时间】:2014-06-05 09:19:39 【问题描述】:

我正在使用 django rest_gramework 序列化程序来转储我的对象的 json:

response = InstallSerializer(Install.objects.all(), many=True).data
return StreamingHttpResponse(response, content_type='application/json')

在哪里

class InstallSerializer(serializers.ModelSerializer):
    modules = ModuleSerializer(many=True)

    class Meta:
        model = Install
        fields = ('id', 'install_name', 'modules')

等等

但是,这个输出不是“可读的”......它全部在一行中。

'id': 1, 'install_name': u'Combat Mission Battle For Normandy', 'modules': ['id': 1, 'name': u'Combat Mission Battle For Normandy', 'versions': ['id': 1, 'name': u'1.00-Mac', 'brzs': [1, 2, 3]]]

有没有办法让序列化器更好地格式化输出?

(用于调试的目视检查)

注意:我刚刚了解到,我输出上面显示的序列化表单的方法甚至不会产生有效的 json,尽管它看起来很相似。您必须执行下面接受的答案中显示的 json.dump 步骤才能获得有效的 json,而且它也很漂亮。

【问题讨论】:

您始终可以使用 Browsable API django-rest-framework.org/topics/browsable-api#urls 进行调试。它以可读格式打印 JSON。 【参考方案1】:

我这样做了:

class PrettyJsonRenderer(JSONRenderer):    
    def get_indent(self, accepted_media_type, renderer_context):
        return 2

然后在您网站的settings.py 文件中指定PrettyJsonRenderer

REST_FRAMEWORK = 
    'DEFAULT_RENDERER_CLASSES': (
        'myapp.util.PrettyJsonRenderer',
    )

【讨论】:

谢谢!我刚刚将 get_indent() 方法添加到我们现有的自定义 JSON Renderer 类中,它运行良好。 谢谢,重写渲染器的想法是关键【参考方案2】:

当您使用rest_framework 时,您不应该自己使用json.dumps,因为渲染器会为您完成这项工作。你看到的数据是python字典,它是序列化器的输出。它不会被 DRF 渲染,因为您正在返回一个 Django StreamingHttpResponse。需要呈现此数据以获取您的 JSON。 您是否有理由绕过 rest_framework 渲染?

否则,这是你的处理程序:

return Response(InstallSerializer(Install.objects.all(), many=True).data)

Responserest_framework.response.Response

如果您的客户端需要漂亮的 json:rest_framework JSONRenderer 支持 indent 参数的 Accept 标头(请参阅 the docs)。

所以当你的客户发送:

Accept: application/json; indent=4

您的 JSON 将被缩进。

【讨论】:

谢谢,我需要吸收这个! 嗯 - 我已经尝试实现这一点,但我得到“accepted_renderer not set on Response”。我把 REST_FRAMEWORK = 'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer') 无济于事.... 我发现我需要在我的处理程序中添加 @api_view(['GET', 'POST']) 注释。【参考方案3】:

除了 Denis Cornehl 的回答之外,您还可以强制打印漂亮的输出,而无需客户端在其 Accept: 标头中指定。相反,当您像这样调用render() 时,您在renderer_context 参数中指定它:

content = JSONRenderer().render(data, renderer_context='indent':4)

通过调整Django Rest Framework's tutorial 中的示例,您可以漂亮地打印所有 JSON 序列化对象:

class JSONResponse(HttpResponse):
    def __init__(self, data, **kwargs):
        content = JSONRenderer().render(data, renderer_context='indent':4)
        kwargs['content_type'] = 'application/json'
        super(JSONResponse, self).__init__(content, **kwargs)

【讨论】:

【参考方案4】:

使用下面的行

import json
return StreamingHttpResponse(json.dumps(response, sort_keys=True, indent=4, separators=(',', ': ')),   mimetype='application/json')

【讨论】:

不错的一个!这似乎也解决了序列化程序 (response) 的原始输出实际上不是有效的 json 的问题,这是我在探索 faouto 指出的选项时才发现的。【参考方案5】:

不确定这是否最适合您的用例,但我发现当我在 ReturnDict 对象的 dict() 上调用 pprint 时,我得到了更易读的结果:

ipdb> type(self.response.body)
<class 'rest_framework.utils.serializer_helpers.ReturnDict'>
ipdb> dict(self.response.body)
'status': 'Open', ..., 'voucher_discounts': []  # all on one line
ipdb> pprint(dict(self.response.body))
'currency': u'EUR',
 'id': 1,
 'lines': [OrderedDict([('url', u'http://testserver/api/baskets/1/lines/1/'), ...]), ...],
 ...
 'voucher_discounts': []

但它仍然不会格式化为“行”中的字典列表。

【讨论】:

【参考方案6】:

您可以在您的视图中添加headers='indent': ' ' 作为响应来执行此操作。试试这个:

class JSONListView(ReadOnlyModelViewSet):
    queryset = YourModel.objects.all()
    serializer_class = YourSerializer

    def get_renderers(self):
        return [JSONRenderer()]

    def get_renderer_context(self):
        serializer = self.get_serializer(self.get_queryset(), many=True)
        response = Response(data=serializer.data, headers='indent': '    ')
        return response

【讨论】:

以上是关于如何从 rest_framework 序列化程序获得漂亮的输出的主要内容,如果未能解决你的问题,请参考以下文章

如何使 rest_framework 序列化器禁止多余的字段?

Django 序列化器与 rest_framework 序列化器

来自 rest_framework modelSerializer 的模型方法

rest_framework-序列化-总结完结篇

rest_framework

Django rest_framework 序列化组件