django - perché l'oggetto request.POST è immutabile?


109

Come chiede il titolo, perché i ragazzi di Django hanno deciso di implementare l'oggetto request.POST con un querydict (che, ovviamente, a sua volta, rende il tutto immutabile?)

So che puoi modificarlo facendo una copia dei dati del post

post = request.POST.copy()

ma perché farlo? Sicuramente sarebbe più semplice lasciare che la cosa sia comunque mutevole? O viene utilizzato anche per qualche altro motivo che potrebbe causare problemi?


1
Perché vuoi che sia mutevole? Puoi prendere i dati da esso e usarli / modificarli nella tua vista. Aggiungendovi dati, è possibile creare l'impressione che request.POSTè stata inviata con più dati di quanti ne siano stati effettivamente.
Simeon Visser

11
Non è che io voglia che sia mutevole. Non più che, diciamo, vorrei che il gelato fosse freddo. Nel caso del gelato però, se non è freddo si scioglie e poi vieni rimproverato per aver fatto un gran casino. Ma con l'oggetto request.POST ... Voglio dire, se ho intenzione di sbagliare il mio codice, lo rovinerò. Non sapevo che ci fosse un endemismo di sviluppatori che aggiungevano dati agli oggetti POST e causavano problemi, quindi sembra una cosa strana da "risolvere".
bharal

Bella domanda; non ci ho mai pensato davvero.
Burhan Khalid,

1
Questo è accaduto sporadicamente per me perché il mio cliente a volte inviava dati JSON (modificabili) e talvolta messaggi URL Form Encoded (immutabili).
owenfi

2
Per i non anglofoni, "mutify" non è una parola: la frase corretta è "puoi modificarla" o "puoi modificarla". Inoltre, non è necessario definire il genere degli sviluppatori: potresti usare "Django team" o "core devs" invece di "guys".
alexmuller

Risposte:


131

È un po 'un mistero, non è vero? Diverse teorie superficialmente plausibili si rivelano errate durante le indagini:

  1. In modo che l' POSToggetto non debba implementare metodi di mutazione? No: l' POSToggetto appartiene alla django.http.QueryDictclasse , che implementa una serie completa di metodi di mutazione tra cui __setitem__, __delitem__, pope clear. Implementa l'immutabilità controllando un flag quando si chiama uno dei metodi di mutazione. E quando chiami il copymetodo ottieni un'altra QueryDictistanza con il flag mutabile attivato.

  2. Per migliorare le prestazioni? No: la QueryDictclasse non ottiene alcun vantaggio in termini di prestazioni quando il flag mutabile è disattivato.

  3. In modo che l' POSToggetto possa essere utilizzato come chiave del dizionario? No: gli QueryDictoggetti non sono modificabili.

  4. In modo che i POSTdati possano essere costruiti pigramente (senza impegnarsi a leggere l'intera risposta), come affermato qui ? Non vedo alcuna prova di ciò nel codice: per quanto ne so, l'intera risposta viene sempre letta, direttamente o tramite MultiPartParserper le multipartrisposte.

  5. Per proteggerti dagli errori di programmazione? Ho visto questo affermato, ma non ho mai visto una buona spiegazione di cosa siano questi errori e di come l'immutabilità ti protegga da essi.

In ogni caso, nonPOST è sempre immutabile : quando la risposta c'è multipart, allora POSTè mutabile. Questo sembra mettere il kibosh sulla maggior parte delle teorie a cui potresti pensare. (A meno che questo comportamento non sia una svista.)

In sintesi, non vedo una chiara motivazione in Django per cui l' POSToggetto sia immutabile per le non multipartrichieste.


Ho notato tonnellate di spigoli vivi come questo in Django. Però deve aver avuto senso per qualcuno prima o poi.
Dan Passaro

2
Ho trovato questo in un'altra risposta di Stack: "E deve essere immutabile in modo che possa essere costruito pigramente. La copia forza il recupero di tutti i dati POST. Fino alla copia, potrebbe non essere tutto recuperato. Inoltre, per un WSGI multi-thread server per funzionare abbastanza bene, è utile se questo è immutabile "
Seaux

12
@Seaux non dovresti leggere le risposte SO pigramente quando intendi commentarle. ;-)
Chris Wesseling

3
@ChrisWesseling Vedo cosa hai fatto lì
Seaux

2
Ancora meglio, il querydict è modificabile quando invio la richiesta facendo causa al client di test django.
user1158559

82

Se la richiesta è il risultato di un forminvio Django , è ragionevole che POST immutablegarantisca l'integrità dei dati tra l' invio del modulo e la convalida del modulo . Tuttavia, se la richiesta non è stata inviata tramite una formpresentazione Django , allora il POST è mutableperché non c'è convalida del modulo.

Puoi sempre fare qualcosa del genere: (come da commento di @ leo-the-mania )

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

3
@ JoshK: Immagino che il commentatore volesse rendere il POST modificabile e lo snippet di codice in questa risposta ha aiutato.
ShreevatsaR

È possibile aggiungere una nuova chiave, un valore ma non è possibile modificare i dati esistenti.
Vamsidhar Muggulla

Bello. E sono sicuro che chiunque usi questo codice sa cosa sta facendo.
John Pang

@VamsidharMuggulla Sia l'aggiunta che la modifica sono possibili. È consentita anche la cancellazione.
Antony Hatchkins

5

Aggiornamento :

Gareth Rees aveva ragione sul fatto che i punti 1 e 3 non erano validi in questo caso. Anche se penso che i punti 2 e 4 siano ancora validi, quindi lascerò qui le tesi.

(Ho notato che l' request.POSToggetto di Pyramid (Pylon) e Django è una qualche forma di MultiDict. Quindi forse è una pratica più comune che rendere request.POSTimmutabile.)


Non posso parlare per i ragazzi di Django, anche se mi sembra che potrebbe a causa di alcuni di questi motivi:

  1. Performance . gli oggetti immutabili sono "più veloci" rispetto a quelli mutabili in quanto consentono sostanziali ottimizzazioni. Un oggetto è immutabile significa che possiamo allocare spazio per esso al momento della creazione e i requisiti di spazio non cambiano. Per questo ha anche cose come l'efficienza della copia e l'efficienza del confronto. Modifica : questo non è il caso diQueryDictcome ha sottolineato Gareth Rees.
  2. Nel caso di request.POST, sembra che nessuna attività sul lato server debba modificare i dati della richiesta . E quindi gli oggetti immutabili sono più adatti, per non parlare del fatto che hanno un vantaggio sostanziale in termini di prestazioni.
  3. Gli oggetti immutabili possono essere usati come dictchiavi, che suppongo potrebbero essere molto utili da qualche parte in Django .. Modifica : il mio errore, immutabile non implica direttamente hashable ; gli oggetti hashable tuttavia, sono tipicamente immutabili pure.
  4. Quando si passa in giro request.POST(specialmente a plug-in di terze parti e fuori), ci si può aspettare che questo oggetto di richiesta dell'utente rimanga invariato.

In qualche modo queste ragioni sono anche risposte generiche a "immutabile vs mutabile?" domanda. Sono certo che nel caso Django ci siano molte più considerazioni sul design rispetto a sopra.


1
L'ultimo caso è davvero importante. Si tratta davvero di sicurezza. Questo è il motivo per cui Django fornisce un sessionsmodo di breve durata per ottenere e modificare i dati tra gli stati.
CppLearner

2
Il tuo punto (1) non può essere la risposta in questo caso, perché POSTè un QueryDictoggetto e questi oggetti non ottengono alcun vantaggio in termini di prestazioni dall'essere immutabili. E il tuo punto (3) non può essere la risposta, perché gli QueryDictoggetti non sono hash e quindi non possono essere usati come chiavi del dizionario.
Gareth Rees,

@ GarethRees Grazie per averli segnalati. Effettivamente mi sbagliavo. Ho aggiornato la mia risposta per correggerli. Avrei dovuto prestare maggiore attenzione QueryDictprima di rispondere.
KZ

7
@CppLearner Il punto di sicurezza sembra discutibile, ad esempiorequests.POST._mutable = True; requests.POST['foo'] = 'bar'; request.POST._mutable = False
Dan Passaro

4

Mi piace che sia immutabile per impostazione predefinita. Come accennato, puoi renderlo mutabile se necessario, ma devi essere esplicito al riguardo. È come "So che posso rendere il mio modulo debugging un incubo, ma so cosa sto facendo ora".


2

L'ho trovato in un commento su Stack Answer https://stackoverflow.com/a/2339963

E deve essere immutabile in modo che possa essere costruito pigramente. La copia forza l'acquisizione di tutti i dati POST. Fino alla copia, potrebbe non essere tutto recuperato. Inoltre, affinché un server WSGI multi-thread funzioni ragionevolmente bene, è utile se non è modificabile


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.