django - warum ist das request.POST-Objekt unveränderlich?

109

Wie der Titel fragt, warum haben die Django-Leute beschlossen, die Anfrage zu implementieren. POST-Objekt mit einem Querydict (was natürlich wiederum das Ganze unveränderlich macht?)

Ich weiß, dass Sie es ändern können, indem Sie eine Kopie der Postdaten erstellen

post = request.POST.copy()

aber warum das? Sicherlich wäre es einfacher, das Ding trotzdem veränderlich zu machen? Oder wird es auch aus einem anderen Grund verwendet, der Probleme verursachen könnte?

Bharal
quelle
1
Warum soll es veränderlich sein? Sie können die Daten daraus entnehmen und in Ihrer Ansicht verwenden / ändern. Durch Hinzufügen von Daten können Sie den Eindruck erwecken, dass request.POSTmehr Daten übermittelt wurden als tatsächlich.
Simeon Visser
11
Es ist nicht so, dass ich möchte , dass es veränderlich ist. Nicht mehr als zum Beispiel möchte ich, dass Eis kalt ist. Im Fall von Eis schmilzt es , wenn es nicht kalt ist, und dann wird man beschimpft, weil man ein großes Durcheinander gemacht hat. Aber mit dem request.POST-Objekt ... Ich meine, wenn ich meinen Code vermasseln will, werde ich ihn vermasseln. Ich war mir nicht bewusst, dass Entwickler endemisch Daten zu POST-Objekten hinzugefügt haben und Probleme verursachen.
Bharal
Gute Frage; habe nie wirklich daran gedacht.
Burhan Khalid
1
Dies kam sporadisch für mich vor, weil mein Client manchmal JSON-Daten (veränderlich) und manchmal URL-formularcodierte (unveränderliche) Nachrichten übermittelte.
Owenfi
2
Für nicht englischsprachige Personen ist "mutifizieren" kein Wort - der richtige Ausdruck lautet "Sie können es mutieren" oder "Sie können es ändern". Es ist auch nicht nötig, die Entwickler zu geschlechtsspezifisch zu behandeln - Sie könnten "Django-Team" oder "Core-Entwickler" anstelle von "Jungs" verwenden.
Alexmüller

Antworten:

131

Es ist ein bisschen ein Rätsel, nicht wahr? Mehrere oberflächlich plausible Theorien erweisen sich bei der Untersuchung als falsch:

  1. Damit das POSTObjekt keine Mutationsmethoden implementieren muss? Nein: Das POSTObjekt gehört zum django.http.QueryDictKlasse , die implementiert ein vollständiger Satz von Mutationsverfahren einschließlich __setitem__, __delitem__, popund clear. Es implementiert Unveränderlichkeit, indem ein Flag überprüft wird, wenn Sie eine der Mutationsmethoden aufrufen. Und wenn Sie die copyMethode aufrufen , erhalten Sie eine andere QueryDictInstanz mit aktiviertem veränderlichen Flag.

  2. Zur Leistungsverbesserung? Nein: Die QueryDictKlasse erhält keinen Leistungsvorteil, wenn das veränderbare Flag deaktiviert ist.

  3. Damit das POSTObjekt als Wörterbuchschlüssel verwendet werden kann? Nein: QueryDictObjekte sind nicht hashbar.

  4. Damit die POSTDaten träge erstellt werden können (ohne die gesamte Antwort zu lesen), wie hier behauptet ? Ich sehe keinen Beweis dafür im Code: soweit ich das beurteilen kann, die Gesamtheit der Antwort wird immer gelesen, entweder direkt oder über MultiPartParserfür multipartAntworten.

  5. Um Sie vor Programmierfehlern zu schützen? Ich habe dies behauptet gesehen, aber ich habe nie eine gute Erklärung dafür gesehen, was diese Fehler sind und wie Unveränderlichkeit Sie vor ihnen schützt.

In jedem Fall POSTist nicht immer unveränderlich : Wenn die Antwort ist multipart, dann POSTist veränderlich. Dies scheint den Kibosh auf die meisten Theorien zu setzen, an die Sie vielleicht denken. (Es sei denn, dieses Verhalten ist ein Versehen.)

Zusammenfassend kann ich in Django keine klare Begründung dafür sehen, dass das POSTObjekt für Nichtanfragen unveränderlich ist multipart.

Gareth Rees
quelle
Ich habe in Django Unmengen solcher Ecken und Kanten bemerkt. Muss aber irgendwann für jemanden Sinn ergeben haben.
Dan Passaro
2
Ich fand dies in einer anderen Stack-Antwort: "Und es muss unveränderlich sein, damit es träge erstellt werden kann. Die Kopie erzwingt das Abrufen aller POST-Daten. Bis zur Kopie werden möglicherweise nicht alle abgerufen. Außerdem für ein Multithread-WSGI Server, um einigermaßen gut zu funktionieren, ist es hilfreich, wenn dies unveränderlich ist "
Seaux
12
@Seaux Sie sollten SO-Antworten nicht träge lesen, wenn Sie sie kommentieren möchten. ;-)
Chris Wesseling
3
@ ChrisWesseling Ich sehe, was Sie dort getan haben
Seaux
2
Noch besser ist, dass der Querydict veränderlich ist, wenn ich die Anfrage an den Django-Testclient versende.
user1158559
82

Wenn die Anfrage das Ergebnis einer Django- formÜbermittlung war, ist es für POST sinnvoll immutable, die Integrität der Daten zwischen der Übermittlung des Formulars und der Validierung des Formulars sicherzustellen . Wenn die Anfrage jedoch nicht über eine Django- formÜbermittlung gesendet wurde , erfolgt POST, mutableda keine Formularvalidierung erfolgt.

Sie können immer so etwas tun: (gemäß dem Kommentar von @ leo-the-manic )

#  .....
mutable = request.POST._mutable
request.POST._mutable = True
request.POST['some_data'] = 'test data'
request.POST._mutable = mutable
# ......
un33k
quelle
3
@JoshK: Ich denke, der Kommentator wollte POST veränderbar machen, und das Code-Snippet in dieser Antwort hat geholfen.
ShreevatsaR
Sie können einen neuen Schlüssel und Wert hinzufügen, aber Sie können die vorhandenen Daten nicht ändern.
Vamsidhar Muggulla
Nett. Und ich bin sicher, wer diesen Code verwendet, weiß, was er oder sie tut.
John Pang
@VamsidharMuggulla Das Hinzufügen und Ändern ist möglich. Auch das Löschen ist erlaubt.
Antony Hatchkins
5

Update :

Gareth Rees hatte Recht, dass die Punkte 1 und 3 in diesem Fall nicht gültig waren. Obwohl ich denke, dass Punkt 2 und 4 noch gültig sind, werde ich diese hier belassen.

(Mir ist aufgefallen, dass das request.POSTObjekt von Pyramid (Pylon) und Django eine Form von ist MultiDict. Vielleicht ist es eine üblichere Praxis, als request.POSTunveränderlich zu machen.)


Ich kann nicht für die Django-Leute sprechen, obwohl es mir aus folgenden Gründen so scheint:

  1. Leistung . unveränderliche Objekte sind "schneller" als veränderbare, da sie wesentliche Optimierungen ermöglichen. Ein Objekt ist unveränderlich. Dies bedeutet, dass wir ihm zum Zeitpunkt der Erstellung Speicherplatz zuweisen können und sich der Speicherplatzbedarf nicht ändert. Es hat auch Dinge wie Kopiereffizienz und Vergleichseffizienz aufgrund dessen. Bearbeiten : Dies ist nicht der Fall,QueryDictwie Gareth Rees betonte.
  2. Im Fall von request.POSTsollte anscheinend keine Aktivität auf der Serverseite erforderlich sein, um die Daten der Anforderung zu ändern . Und daher sind unveränderliche Objekte besser geeignet, ganz zu schweigen davon, dass sie einen erheblichen Leistungsvorteil haben.
  3. Unveränderliche Objekte können als dictSchlüssel verwendet werden, was vermutlich irgendwo in Django sehr nützlich sein könnte. Bearbeiten : Mein Fehler, unveränderlich bedeutet nicht direkt Hashable ; Hash- Objekte sind jedoch normalerweise auch unveränderlich .
  4. Wenn Sie weitergeben request.POST(insbesondere an Plugins von Drittanbietern und Outs), können Sie davon ausgehen, dass dieses Anforderungsobjekt des Benutzers unverändert bleibt.

In gewisser Weise sind diese Gründe auch generische Antworten auf "unveränderlich gegen veränderlich?" Frage. Ich bin sicher, dass es im Fall Django viel mehr Überlegungen zum Design gibt als oben.

KZ
quelle
1
Der letzte Fall ist wirklich wichtig. Es geht wirklich um Sicherheit. Aus diesem Grund bietet Django eine sessionskurzlebige Möglichkeit, Daten zwischen Staaten abzurufen und zu ändern.
CppLearner
2
Ihr Punkt (1) kann in diesem Fall nicht die Antwort sein, da POSTes sich um ein QueryDictObjekt handelt und diese Objekte keinen Leistungsvorteil erhalten, wenn sie unveränderlich sind. Und Ihr Punkt (3) kann nicht die Antwort sein, da QueryDictObjekte nicht hashbar sind und daher nicht als Wörterbuchschlüssel verwendet werden können.
Gareth Rees
@GarethRees Vielen Dank für den Hinweis. In der Tat habe ich mich geirrt. Ich habe meine Antwort aktualisiert, um diese zu korrigieren. Ich hätte mehr Aufmerksamkeit schenken sollen, QueryDictbevor ich antwortete.
KZ
7
@CppLearner Der Sicherheitspunkt scheint strittig, zBrequests.POST._mutable = True; requests.POST['foo'] = 'bar'; request.POST._mutable = False
Dan Passaro
4

Ich mag es, wenn es standardmäßig unveränderlich ist. Wie bereits erwähnt, können Sie es bei Bedarf veränderbar machen, müssen dies jedoch explizit angeben. Es ist wie "Ich weiß, dass ich mein Formular zum Debuggen zu einem Albtraum machen kann, aber ich weiß, was ich jetzt tue."

pawelmech
quelle
2

Ich habe dies in einem Kommentar zu Stack Answer https://stackoverflow.com/a/2339963 gefunden

Und es muss unveränderlich sein, damit es träge gebaut werden kann. Die Kopie erzwingt das Abrufen aller POST-Daten. Bis zur Kopie wird möglicherweise nicht alles abgerufen. Damit ein Multithread-WSGI-Server einigermaßen gut funktioniert, ist es hilfreich, wenn dies unveränderlich ist

Seaux
quelle