【问题标题】:Django's Querydict bizarre behavior: bunches POST dictionary into a single keyDjango 的 Querydict 奇怪行为:将 POST 字典捆绑成一个键
【发布时间】:2011-06-11 12:36:21
【问题描述】:

在 django 中使用测试客户端时,我遇到了一个非常奇怪的行为。

我正在使用 POST 将数据发送到我的 django 应用程序。我通常通过 iPhone 应用程序和/或测试 html 表单执行此操作。在服务器端,我是这样处理的:

def handle_query(request):
   print request
   q = con.QueryLog()
   q.ID = request.POST.get('ID', '')
   q.device = request.POST.get('device-model', '')
   ....

该打印语句看起来像您所期望的那样,即发布请求中的每个参数都转换为字典中的键:

POST: QueryDict: {u'app-version': [u'3.0'], u'server-version': [u'v3d0'],

但是,我开始使用 Django 的测试客户端编写一些测试,无论我尝试什么,我在 post 请求中发送的 POST 参数字典都会被捆绑到 QueryDict 中的一个键中。请允许我用一些代码来说明:

类 SearchTest(TestCase): 默认设置(自我): 通过

def test_search(self):
    request = HttpRequest()
    data = '{"amzn_locale": "com"}'
    # request._raw_post_data = data
    resp = self.client.post(
        '/is/', 
        data=data,
        content_type='application/x-www-form-urlencoded',
        # content_type='application/json',
        )

服务器端同样的打印语句显示字典莫名其妙的分组成字符串:

POST: QueryDict: {u'{"amzn_locale":"com"}': [u'']}>,

如果我将数据设置为实际的字典,同样的事情

data = {"amzn_locale": "com"}

设置 request._raw_post_data 不会改变任何东西。也不会改变

content_type='application/json'

任何帮助将不胜感激。从这个stackoverflow问题看来我不是第一个遇到这个问题的人 iphone Json POST request to Django server creates QueryDict within QueryDict

【问题讨论】:

    标签: python django rest post


    【解决方案1】:

    问题在于您提供的是 content_type。既然你这样做了,客户就会期待一个像

    这样的urlencoded字符串
    "username=hi&password=there&this_is_the_login_form=1"
    

    而不是像字典一样

    {'username': 'hi', 'password': 'there', 'this_is_the_login_form': 1}
    

    如果你删除 content_type kwarg 你会没事的。

    编辑:事实证明,如果您传入除MULTIPART_CONTENT 之外的任何 content_type,测试客户端将查找 url 编码的字符串 - content_type 将仅用于确定用于编码该 url 的字符集-编码字符串。这记录在here。相关位为:

    如果您提供 content_type(例如,XML 有效负载的 text/xml),数据内容将在 POST 请求中按原样发送,使用 HTTP Content-Type 标头中的 content_type。

    如果您不提供 content_type 的值,则 data 中的值将以 multipart/form-data 的内容类型传输。在这种情况下,数据中的键值对将被编码为多部分消息,并用于创建 POST 数据负载。

    【讨论】:

      【解决方案2】:

      编辑:当然,就在我开始查看的那一行上方是正确答案。 post_data 根据 content_type 以不同方式处理。请参阅下面的答案。无需应用以下更改。

      所以看起来正在发生的事情是,您传递给 post 的数据 dict 立即被字符串编码函数扁平化为 dict 的字符串表示形式,稍后 QueryDict 无法读取。我不知道预期的行为是什么,但是如果您在发布数据被序列化之前对其进行 urlencode,那么它至少应该以所需的形式到达 QueryDict。在 django/test/client.py 我们看到第 244 行

      post_data = smart_str(data, encoding=charset)
      

      这只是扁平化字典并序列化它。一个可能的解决方法是在序列化之前应用与 GET 相同的格式,因此

      post_data = smart_str(urlencode(data, doseq=True), encoding=charset)
      

      这对我来说似乎是合理的,尽管我不能保证它不会在其他地方产生后果。看起来您可以在调用 client.post 之前在代码中进行上述转换,但我还没有测试过。

      【讨论】:

        【解决方案3】:

        但是您将其声明为字符串 - 您在 data 的值周围加上了单引号。

        【讨论】:

        • 没关系,看第二种提交数据的方式。即使是分组。
        猜你喜欢
        • 2015-02-15
        • 1970-01-01
        • 1970-01-01
        • 2011-11-22
        • 2022-11-22
        • 1970-01-01
        • 2021-03-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多