在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', '')
....
这个print语句看起来像你期望的那样,即post请求中的每个参数都变成了字典中的一个键:
POST:QueryDict:{u'app-version':[u'3.0'],u'server-version':[u'v3d0'],
然而,我开始使用Django的测试客户端编写一些测试,无论我尝试什么,我在post请求中发送的POST参数字典都会聚集到QueryDict
中的单个密钥中。请允许我用一些代码来说明:
类SearchTest(TestCase): def setUp(self): 通
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',
)
服务器端的相同print语句显示字典无法解释为字符串:
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
答案 0 :(得分:7)
问题是你提供的是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),则数据内容将使用HTTP Content-Type标头中的content_type在POST请求中按原样发送。
如果您没有为content_type提供值,则数据中的值将以内容类型multipart / form-data传输。在这种情况下,数据中的键值对将被编码为多部分消息,并用于创建POST数据有效负载。
答案 1 :(得分:1)
编辑:当然,正好在我开始看的那一行上面就是正确的答案。 post_data基于content_type以不同方式处理。请参阅以下答案。无需应用以下更改。
所以看起来正在发生的事情是你传入post的数据被字符串编码函数立即变为dict的字符串表示,后面的QueryDict无法读取。我不知道预期的行为是什么,但是如果你在序列化之前对帖子数据进行了urlencode,那么它至少应该在QueryDict中以所需的形式到达。在django / test / client.py中我们看到第244行
post_data = smart_str(data, encoding=charset)
它只是使dict变平并将其序列化。可能的解决方法是在序列化之前应用与GET使用相同的格式,因此
post_data = smart_str(urlencode(data, doseq=True), encoding=charset)
这对我来说似乎是合理的,但我不能保证它在其他地方没有后果。看起来您可以在调用client.post之前在代码中执行上述转换,但我还没有测试过。
答案 2 :(得分:0)
但是您将其声明为字符串 - 您在data
的值周围有单引号。