2011-06-11 90 views
5

在django中使用测试客户端时,我遇到了一个非常奇怪的行为。Django的Querydict怪异行为:将POST字典串成单个键

我正在使用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(测试用例): DEF设置(个体经营): 通

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' 

任何帮助将不胜感激。从这个计算器问题,好像我没有碰到这个 iphone Json POST request to Django server creates QueryDict within QueryDict

+0

Gabi感谢编辑 – Andres 2011-06-11 12:48:20

回答

7

问题是你正在提供一个content_type。既然你这样做了,客户期待一个urlencoded的串像

"username=hi&password=there&this_is_the_login_form=1" 

,而不是像字典

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

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

编辑:事实证明,如果您传入的任何content_type不是MULTIPART_CONTENT - content_type只会用于找出用于编码该url的字符集,编码字符串。这记录在here。相关位读取:

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

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

+0

感谢您的帮助;) – Andres 2011-06-12 20:09:27

0

的第一人,但你宣布它作为一个字符串 - 你身边的data值单引号。

+0

没关系,看看提交数据的第二种方式。即使是分组。 – Andres 2011-06-11 12:50:50

1

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

所以它看起来像是发生了什么是你传递给后期的数据字典正在被字符串编码函数立即变成字典的字符串表示形式,后来QueryDict不能读取。我不知道预期的行为是什么,但是如果你在发布数据之前对它进行urlen编码,那么它至少应该在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之前在代码中完成上述转换,但是我没有测试过。