序列化可选的嵌套结构:QueryDict和normal dict之间的区别? [英] Serializing optionally nested structures: Difference between QueryDict and normal dict?
问题描述
这是一个示例序列化程序:
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 =
class Meta:
fields =('a','child')
def perform_create(self,serializer):
#TODO:创建嵌套对象。
pass
(我省略了perform_create中的代码,因为它与问题)。
现在,传递一个正常的dict作为数据参数工作正常:
code> 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 '],'field_c':[你需要这个字段']}}
在实际的网站上,API得到一个正常的dict,因此工作正常。在测试过程中,使用像 client.post('url',data = dict(field_a = 3))
这样的东西会导致一个QueryDict被传递给视图,因此不工作。
所以我的问题是:QueryDict和normal dict有什么区别?或者我接近这个错误的方式?
DRF定义了多个解析器类,用于解析具有不同媒体的请求内容类型。
request.data
通常是一个 QueryDict
或正常字典取决于用于解析请求内容的解析器。
- JSONParser:
它解析JSON请求内容,即以 .media_type
为 application / json
。
- FormParser
它解析HTML表单内容。这里, request.data
填充了一个 QueryDict
的数据。这些有code> .media_type as application / x-www-form-urlencoded
。
- MultiPartParser
它解析多部分HTML表单内容,支持文件上传。此外, request.data
都填充了一个 QueryDict
。这些
.media_type
as multipart / form-data
。
- FileUploadParser
它解析原始文件上传内容。 request.data
属性是一个包含上传文件的单键文件
的字典 。
DRF 确定解析器?
当DRF访问 request.data
,它检查传入请求中的 Content-Type
头,然后确定用于解析请求内容的解析器。 / p>
发送数据时,您需要设置 Content-Type
标题,否则将使用多部分或形式解析器来解析请求内容,并在 request.data
中为您提供 QueryDict
而不是字典。
根据DRF文档,
如果没有设置内容类型,大多数客户端将默认使用
'application / x-www-form-urlenc oded'
,可能不是你想要的。
所以当发送json编码数据时,也设置 Content-Type
头到 application / json
,然后它将按预期工作。
为什么request.data有时是 QueryDict
,有时 dict
?
这是因为不同的编码具有不同的数据结构和属性。
例如,表单数据是一个支持多个相同值的键的编码,而json不支持。
另外在这种情况下的JSON数据, request.DATA
可能不是一个 dict
,它可能是一个列表或任何其他json原语。
查看这个 Google Groups线程大致相同。
您需要做什么?
当 POSTing
时,您可以在测试中添加 format ='json'
数据将设置内容类型以及序列化数据正确。
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')
I'm running into weird behavior when writing nested structures with django-rest and then trying to test them using django-rest's test client. The nested child object should be optional.
Here's a sample serializer:
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
(I've omitted the code in perform_create, as it's not relevant to the question).
Now, passing a normal dict as data argument works just fine:
ser = ParentSerializer(data=dict(field_a=3))
ser.is_valid(raise_exception=True)
But passing a QueryDict instead will fail:
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.']}}
On the actual web site, the API gets a normal dict and thus works fine. During testing however, using something like client.post('url', data=dict(field_a=3))
will result in a QueryDict being passed to the view, and hence not work.
So my question is: what's the difference between the QueryDict and normal dict? Or am I approaching this the wrong way?
DRF defines multiple parser classes for parsing the request content having different media types.
request.data
will normally be a QueryDict
or a normal dictionary depending on the parser used to parse the request content.
- JSONParser:
It parses the JSON request content i.e. content with .media_type
as application/json
.
- FormParser
It parses the HTML form content. Here, request.data
is populated with a QueryDict
of data. These have .media_type
as application/x-www-form-urlencoded
.
- MultiPartParser
It parses multipart HTML form content, which supports file uploads. Here also, both request.data
is populated with a QueryDict
. These have
.media_type
as multipart/form-data
.
- FileUploadParser
It parses raw file upload content. The request.data
property is a dictionary with a single key file
containing the uploaded file.
How does DRF determines the parser?
When DRF accesses the request.data
, it examines the Content-Type
header on the incoming request and then determines which parser to use to parse the request content.
You will need to set the Content-Type
header when sending the data otherwise it will use either a multipart or a form parser to parse the request content and give you a QueryDict
in request.data
instead of a dictionary.
As per DRF docs,
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.
So when sending json encoded data, also set the Content-Type
header to application/json
and then it will work as expected.
Why request.data is sometimes QueryDict
and sometimes dict
?
This is done because different encodings have different datastructures and properties.
For example, form data is an encoding that supports multiple keys of the same value, whereas json does not support that.
Also in case of JSON data, request.DATA
might not be a dict
at all, it could be a list or any of the other json primitives.
Check out this Google Groups thread about the same.
What you need to do?
You can add format='json'
in the tests when POSTing
the data which will set the content-type as well as serialize the data correctly.
client.post('url', format='json', data=dict(field_a=3))
You can also send JSON-encoded content with content-type
argument.
client.post('url', json.dumps(dict(field_a=3)), content_type='application/json')
这篇关于序列化可选的嵌套结构:QueryDict和normal dict之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!