Django 视图:request.data 什么时候是 dict 与 QueryDict?
Django Views: When is request.data a dict vs a QueryDict?
我 运行 在这个问题上遇到了一些麻烦,request.data 有时是一个 dict
(尤其是在测试时),有时是一个 QueryDict
实例(当使用卷曲)。
这尤其是一个问题,因为在像这样使用 curl 调用视图时显然存在很大差异:
curl -X POST --data "some_float=1.23456789012123123" "http://localhost:8000/myview"
或者像这样使用 django_webtest 客户端:
class APIViewTest(WebTest):
def test_testsomething(self):
self.app.post(url=url, params=json.dumps({some_float=1.26356756467}))
然后像这样将 QueryDict 转换为字典
new_dict = dict(**request.data)
my_float = float(new_dict['some_float'])
在测试中一切正常,因为 request.data
是一个 dict
,但在生产中视图崩溃,因为 new_dict['some_float']
实际上是一个只有一个元素的列表,而不是预计浮动。
我考虑过这样解决问题:
if type(request.data) is dict:
new_dict = dict(**request.data)
else:
new_dict = dict(**request.data.dict())
这感觉很不对,因为测试只会测试第 2 行,而(部分?全部?)生产代码会 运行 第 4 行。
因此,虽然我想知道为什么 QueryDict 会以这种方式运行,但我首先想知道 response.data 为何以及何时成为 QueryDict
。以及我如何使用 Django 测试来模拟这种行为。生产和测试系统的不同条件总是很麻烦,有时是不可避免的,但在这种情况下,我觉得它可以被修复。或者这是与 django_webtest 相关的特定问题?
您的测试并未反映您实际的 curl 调用。
在您的测试中,您 post JSON,然后可作为来自 request.data
的字典使用。但是您的 curl 调用 posts 标准表单数据,它可作为 QueryDict 使用。此行为由视图的 parsers
属性或 DEFAULT_PARSER_CLASSES 设置管理 - 进一步注意,这是 django-rest-framework 专门提供的功能,而不是 Django 本身。
真的,你应该测试你正在做的同样的事情;从 curl 发送 JSON 或将测试发送到 post form-data.
当你的请求content_type是"application/x-www-form-urlencoded"时,request.Data变成了QueryDict。
请参阅 FormParser class。
https://github.com/encode/django-rest-framework/blob/master/rest_framework/parsers.py
和
QueryDict 有获取列表的方法。但它无法获取字典值。
将名称 str 转换为数组。
<input name="items[name]" value="Example">
<input name="items[count]" value="5">
https://pypi.org/project/html-json-forms/
并定义自定义表单文件。
class CustomFormParser(FormParser):
"""
Parser for form data.
"""
media_type = 'application/x-www-form-urlencoded'
def parse(self, stream, media_type=None, parser_context=None):
"""
Parses the incoming bytestream as a URL encoded form,
and returns the resulting QueryDict.
"""
parser_context = parser_context or {}
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
data = QueryDict(stream.read(), encoding=encoding)
return parse_json_form(data.dict()) # return dict
并覆盖 DEFAULT_PARSER_CLASSES。
https://www.django-rest-framework.org/api-guide/settings/#default_parser_classes
我 运行 在这个问题上遇到了一些麻烦,request.data 有时是一个 dict
(尤其是在测试时),有时是一个 QueryDict
实例(当使用卷曲)。
这尤其是一个问题,因为在像这样使用 curl 调用视图时显然存在很大差异:
curl -X POST --data "some_float=1.23456789012123123" "http://localhost:8000/myview"
或者像这样使用 django_webtest 客户端:
class APIViewTest(WebTest):
def test_testsomething(self):
self.app.post(url=url, params=json.dumps({some_float=1.26356756467}))
然后像这样将 QueryDict 转换为字典
new_dict = dict(**request.data)
my_float = float(new_dict['some_float'])
在测试中一切正常,因为 request.data
是一个 dict
,但在生产中视图崩溃,因为 new_dict['some_float']
实际上是一个只有一个元素的列表,而不是预计浮动。
我考虑过这样解决问题:
if type(request.data) is dict:
new_dict = dict(**request.data)
else:
new_dict = dict(**request.data.dict())
这感觉很不对,因为测试只会测试第 2 行,而(部分?全部?)生产代码会 运行 第 4 行。
因此,虽然我想知道为什么 QueryDict 会以这种方式运行,但我首先想知道 response.data 为何以及何时成为 QueryDict
。以及我如何使用 Django 测试来模拟这种行为。生产和测试系统的不同条件总是很麻烦,有时是不可避免的,但在这种情况下,我觉得它可以被修复。或者这是与 django_webtest 相关的特定问题?
您的测试并未反映您实际的 curl 调用。
在您的测试中,您 post JSON,然后可作为来自 request.data
的字典使用。但是您的 curl 调用 posts 标准表单数据,它可作为 QueryDict 使用。此行为由视图的 parsers
属性或 DEFAULT_PARSER_CLASSES 设置管理 - 进一步注意,这是 django-rest-framework 专门提供的功能,而不是 Django 本身。
真的,你应该测试你正在做的同样的事情;从 curl 发送 JSON 或将测试发送到 post form-data.
当你的请求content_type是"application/x-www-form-urlencoded"时,request.Data变成了QueryDict。
请参阅 FormParser class。
https://github.com/encode/django-rest-framework/blob/master/rest_framework/parsers.py
和
QueryDict 有获取列表的方法。但它无法获取字典值。
将名称 str 转换为数组。
<input name="items[name]" value="Example">
<input name="items[count]" value="5">
https://pypi.org/project/html-json-forms/
并定义自定义表单文件。
class CustomFormParser(FormParser):
"""
Parser for form data.
"""
media_type = 'application/x-www-form-urlencoded'
def parse(self, stream, media_type=None, parser_context=None):
"""
Parses the incoming bytestream as a URL encoded form,
and returns the resulting QueryDict.
"""
parser_context = parser_context or {}
encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
data = QueryDict(stream.read(), encoding=encoding)
return parse_json_form(data.dict()) # return dict
并覆盖 DEFAULT_PARSER_CLASSES。
https://www.django-rest-framework.org/api-guide/settings/#default_parser_classes