在使用 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 ,否则它将使用多部分或表单解析器来解析请求内容并给你一个 QueryDict
在request.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/