2012-09-26 25 views
79

正如標題問,爲什麼Django的傢伙決定實施具有的QueryDict的request.POST對象(其中,當然,反過來又使一成不變的整個事情?)django - 爲什麼request.POST對象是不可變的?

我知道你可以mutify它通過複製發佈數據

post = request.POST.copy() 

但爲什麼要這樣做?無論如何,只要讓事情變得可變,肯定會更簡單一些?或者它也被用於其他一些可能導致問題的原因?

+1

爲什麼你想要它是可變的?您可以從中獲取數據並在視圖中使用/修改數據。通過向其添加數據,您可以創建一個「request.POST」已被提交的數據比實際數據更多的印象。 –

+7

這不是我*想*它是可變的。不過,比方說,我想要冰淇淋冷。在冰淇淋的情況下,如果它不冷,它會融化,然後你會因爲製造一個大混亂而被罵。但有了request.POST對象......我的意思是,如果我要搞砸我的代碼,我會把它搞砸。我並不知道有開發人員將數據添加到POST對象和導致問題的特徵,因此定位到「修復」似乎很奇怪。 – bharal

+0

不錯的問題;從來沒有想過它。 –

回答

107

這有點神祕,不是嗎?一些表面上似是而非的理論被證明是錯了調查:

  1. 從而使POST對象沒有實現突變的方法呢?否:POST對象屬於django.http.QueryDict class,該對象實現了全套突變方法,包括__setitem__,__delitem__,popclear。當你調用一個突變方法時,它通過檢查一個標誌來實現不變性。當您調用copy方法時,您將獲得另一個QueryDict實例,其中打開了可變標誌。

  2. 爲了提高性能?否:當關閉可變標誌時,QueryDict類不會獲得性能優勢。

  3. 這樣POST對象可以用作字典鍵嗎?編號:QueryDict對象不可排除。

  4. 因此,POST數據可以建立懶惰(不承諾讀取整個響應),as claimed here?我在代碼中看不到這種證據:據我所知,整個響應總是被讀取,即directly,或者通過MultiPartParser獲得multipart響應。

  5. 爲了防止編程錯誤?我已經看到這個說法,但我從來沒有看到這些錯誤是什麼的好解釋,以及不變性如何保護你免受它們的侵害。

在任何情況下,POST並不總是不變的:當響應是multipart,然後POST是可變的。這似乎把kibosh放在你可能想到的大多數理論上。 (除非這種行爲是一個疏忽。)

綜上所述,我看不出有什麼明確的理由在Django爲POST對象是不可改變的非multipart請求。

+0

我注意到在Django中有像這樣粗糙的邊緣。不過,在某些時候,一定對某個人有意義。 –

+2

我在另一個Stack中發現了這個答案:「它必須是不可變的,所以它可以被懶惰地構建,拷貝會獲得所有的POST數據,直到拷貝完成時,它可能不會被全部取出。 WSGI服務器工作得相當好,這是有益的,如果這是不可改變的「 – Seaux

+0

@Seaux:請參閱我的要點#4。 –

5

更新

加雷思·雷斯是正確的,點1 & 3例無效在這種情況下。雖然我認爲第2點和第4點仍然有效,因此我將在此留下論文。

(我注意到,這兩個金字塔(塔)和Django中的request.POST對象是某種形式的MultiDict。因此,也許這是一個比較普遍的做法不是讓request.POST不可改變的。)


我可以「T代言Django的傢伙,雖然在我看來,這可能是因爲一些原因:

  1. 性能自動。不可變對象比可變對象「更快」,因爲它們允許大量優化。一個對象是不可變的,意味着我們可以在 創建時間處爲它分配空間,並且空間需求不會改變。因爲它也有複製效率和比較效率。 編輯:正如Gareth Rees指出的,QueryDict並非如此。
  2. request.POST的情況下,服務器端似乎沒有活動需要更改請求的數據的。因此不變的對象更適合,更不用說它們具有實質性的優勢。
  3. 不可變對象可以作爲 dict鍵,我想 可能是非常有用的地方在Django .. 編輯:我的錯誤,不可改變並不直接意味着可哈希;然而,可排列的對象通常也是不可變的
  4. 當你傳遞request.POST(尤其是第三方插件)時,你可以期望來自用戶的這個請求對象將保持不變。

在某些方面,這些原因也是對「不可變vs可變?」的通用答案。題。我確信Django案例中有更多的設計考慮。

+1

最後一種情況非常重要。這關乎安全。這就是爲什麼Django提供'會話',這是短暫的獲取和修改狀態之間的數據的方式。 – CppLearner

+2

你的觀點(1)不能成爲這種情況下的答案,因爲'POST'是一個['QueryDict'對象](https://github.com/django/django/blob/master/django/http/__init__ .py#L371),並且這些對象不會因爲不可變而受益。而你的觀點(3)不能成爲答案,因爲'QueryDict'對象是不可散列的,所以不能用作字典鍵。 –

+0

@GarethRees感謝您指出這些。的確我錯了。我更新了我的答案以糾正這些問題。在我回復之前,我應該更多地關注'QueryDict'。 –

61

如果請求一個Django form提交的結果,那麼它是合理的POST爲immutable以確保數據形式提交和形式驗證之間的完整性。然而,如果請求是不經由一個Django form提交發送,則POST是mutable因爲沒有表單驗證。

你總是可以做這樣的事情:(按@leo-the-manic's comment

# ..... 
mutable = request.POST._mutable 
request.POST._mutable = True 
request.POST['some_data'] = 'test data' 
request.POST._mutable = mutable 
# ...... 
+2

@JoshK:我猜這個評論者想讓POST變爲可變的,並且這個答案中的代碼片段有所幫助。 – ShreevatsaR

+0

您可以添加新的鍵值,但不能更改現有數據。 –

2

我發現這在堆棧評論回答https://stackoverflow.com/a/2339963

而且它必須是不可變的,這樣它可以懶洋洋地建造。複製強制獲取所有POST數據。在拷貝之前,它可能不會被全部取出。此外,對於多線程WSGI服務器工作得相當好,這是有幫助的,如果這是不可變的

3

我喜歡它默認情況下是不可變的。 正如你指出的那樣,如果你需要,你可以使它變化,但你必須明確它。這就像'我知道我可以讓我的表單調試一場噩夢,但我知道我現在正在做什麼。'

相關問題