Django视图:request.data何时是dict还是QueryDict?

时间:2018-11-08 10:55:40

标签: python django django-rest-framework django-webtest

我在这个问题上遇到了麻烦,那个request.data有时是一个dict(尤其是在测试时),有时是一个QueryDict实例(使用curl时)。

这是一个特别的问题,因为使用如下所示的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转换为类似这样的dict

new_dict = dict(**request.data)
my_float = float(new_dict['some_float'])

一切正常,因为request.datadict,但在测试中一切正常,但是在生产中,视图崩溃了,因为new_dict['some_float']实际上是一个包含一个元素的列表,而不是预期的a浮动。

我已经考虑过像这样解决问题:

    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有关的特定问题?

2 个答案:

答案 0 :(得分:2)

您的测试并不反映您的实际curl调用。

在测试中,您发布JSON,然后可以从request.data中将其作为字典使用。但是您的curl调用将发布标准表单数据,这些数据可以作为QueryDict使用。此行为由视图的parsers属性或DEFAULT_PARSER_CLASSES设置管理-还要注意,这是django-rest-framework专门提供的功能,您应该在问题中标记该功能,而不是Django本身。 / p>

真的,您应该测试与所做的相同的事情;从curl发送JSON或进行测试以发布表单数据。

答案 1 :(得分:0)

当您的请求content_type为“ application / x-www-form-urlencoded”时,request.Data成为QueryDict。

请参阅FormParser类。
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/

并定义自定义表单paser。

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

相关问题