python - 序列化可选的嵌套结构 : Difference between QueryDict and normal dict?

标签 python django django-rest-framework

在使用 django-rest 编写嵌套结构然后尝试使用 django-rest 的测试客户端测试它们时,我遇到了奇怪的行为。嵌套的子对象应该是可选的。

这是一个示例序列化器:

from rest_framework import serializers

class OptionalChildSerializer(serializers.Serializer):
    field_b = serializers.IntegerField()
    field_c = serializers.IntegerField()

    class Meta:
        fields = ('field_b', 'field_c', )

class ParentSerializer(serializers.Serializer):
    field_a = serializers.IntegerField()
    child = OptionalChildSerializer(required=False, many=False)

    class Meta:
        fields = ('a', 'child',)

    def perform_create(self, serializer):
        # TODO: create nested object.
        pass

(我省略了 perform_create 中的代码,因为它与问题无关)。

现在,将普通的字典作为数据参数传递就可以了:

ser = ParentSerializer(data=dict(field_a=3))
ser.is_valid(raise_exception=True)

但是传递一个 QueryDict 会失败:

from django.http import QueryDict
ser = ParentSerializer(data=QueryDict("field_a=3"))
ser.is_valid(raise_exception=True)

ValidationError: {'child': {'field_b': [u'This field is required.'], 'field_c': [u'This field is required.']}}

在实际的网站上,API 得到一个正常的字典,因此工作正常。然而,在测试期间,使用诸如 client.post('url', data=dict(field_a=3)) 之类的东西将导致 QueryDict 被传递到 View ,因此不起作用。

所以我的问题是:QueryDict 和普通字典有什么区别?还是我处理方法不对?

最佳答案

DRF定义了多个解析器类来解析不同媒体类型的请求内容。

request.data通常是 QueryDict或普通字典,具体取决于用于解析请求内容的解析器。

  • JSON 解析器:

它解析 JSON 请求内容,即带有 .media_type 的内容作为application/json .

  • 表单解析器

它解析 HTML 表单内容。在这里, request.data填充有 QueryDict数据。 这些有 .media_type作为application/x-www-form-urlencoded .

  • 多部分解析器

解析多部分HTML表单内容,支持文件上传。这里也有 request.data填充有 QueryDict 。这些有 .media_type作为multipart/form-data .

  • 文件上传解析器

它解析原始文件上传内容。 <强> request.data属性是一个字典,只有一个键 file包含上传的文件。

DRF如何determines解析器?

当 DRF 访问 request.data 时, 它检查 Content-Type传入请求的 header ,然后确定使用哪个解析器来解析请求内容。

您需要设置 Content-Type发送数据时 header ,否则它将使用多部分或表单解析器来解析请求内容并给你一个 QueryDictrequest.data而不是字典。

根据 DRF 文档,

If you don't set the content type, most clients will default to using 'application/x-www-form-urlencoded', which may not be what you wanted.

所以在发送json编码数据的时候,还要设置Content-Type标题为 application/json然后它将按预期工作。

为什么 request.data 有时是 QueryDict有时 dict ?

这样做是因为不同的编码具有不同的数据结构和属性。

例如,表单数据是一种编码,支持多个相同值的键,而json不支持。

同样在 JSON 数据的情况下,request.DATA可能不是 dict总之,它可以是一个列表或任何其他 json 原语。

看看这个 Google Groups thread差不多。

你需要做什么?

您可以添加 format='json'在测试时 POSTing将设置内容类型以及正确序列化数据的数据。

client.post('url', format='json', data=dict(field_a=3))

您还可以使用 content-type 发送 JSON 编码的内容争论。

client.post('url', json.dumps(dict(field_a=3)), content_type='application/json')

关于python - 序列化可选的嵌套结构 : Difference between QueryDict and normal dict?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31759133/

相关文章:

python - Django 写入带有一些空字段的 csv

django - 基于其他字段的模型字段?

python - 如何在 Django Rest 框架中设置 View

python - 在 Django 模型中保存 Facebook 图片(REST Social Oauth2)

python - PIL 的舍入误差

python - sklearn 的 PCA 实现是否保留输入顺序?

python - 无法将创建不同子文件夹的不同文本文件放入主文件夹中

PythonAnywhere 脚本调度程序不工作

Django 管理员 : How to customize one field in fieldsets?

Django:如何限制模型列表对其所有者的访问权限?