2011-06-11 45 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之前在代碼中完成上述轉換,但是我沒有測試過。