2012-09-26 21 views
79

Como el título se pregunta, ¿por qué los chicos Django decide implementar el objeto request.POST con un querydict (que, por supuesto, a su vez, hace que todo sea inmutable?)django: ¿por qué el objeto request.POST es inmutable?

sé que puedes mutify al hacer una copia de los datos de la publicación

post = request.POST.copy() 

pero ¿por qué hacer esto? Sin duda, sería más simple simplemente permitir que la cosa sea mutable de todos modos. ¿O se está utilizando por alguna otra razón que también podría causar problemas?

+1

¿Por qué quieres que sea mutable? Puede tomar los datos de él y usarlos/modificarlos en su vista. Al agregarle datos, puede crear la impresión de que se ha enviado 'request.POST' con más datos de los que realmente ha sido. –

+7

No es que yo * quiera * que sea mutable. No más de, digamos, que quisiera que el helado estuviera frío. Sin embargo, en el caso de los helados, si * no es * frío se derrite y luego te regañan por hacer un gran desastre. Pero con el objeto request.POST ... Quiero decir, si voy a estropear mi código, lo voy a arruinar. No sabía que había una endémica de desarrolladores que agregaban datos a los objetos POST y Causar problemas, por lo que parece una cosa extraña para "arreglar". – bharal

+0

Buena pregunta; nunca pensé en eso realmente. –

Respuesta

107

Es un misterio, ¿no?Varias teorías superficialmente plausible llegar a ser malo en la investigación:

  1. modo que el objeto POST no tiene que poner en práctica procedimientos de mutación? No: el objeto POST pertenece al django.http.QueryDict class, que implementa un conjunto completo de métodos de mutación, incluidos __setitem__, __delitem__, pop y clear. Implementa la inmutabilidad al marcar una bandera cuando llamas a uno de los métodos de mutación. Y cuando llamas al método copy obtienes otra instancia QueryDict con la bandera mutable encendida.

  2. Para la mejora del rendimiento? No: la clase QueryDict no obtiene ningún beneficio de rendimiento cuando la bandera mutable está desactivada.

  3. ¿Para que el objeto POST se pueda utilizar como una clave de diccionario? No: QueryDict los objetos no son lavables.

  4. Para que los datos POST puedan construirse perezosamente (sin comprometerse a leer toda la respuesta), as claimed here? No veo evidencia de esto en el código: por lo que puedo decir, toda la respuesta siempre se lee, ya sea directly, o a través de MultiPartParser para respuestas multipart.

  5. ¿Para protegerlo contra errores de programación? He visto esto reclamado, pero nunca he visto una buena explicación de lo que son estos errores, y cómo la inmutabilidad te protege contra ellos.

En cualquier caso, es POSTno siempre inmutable: cuando la respuesta es multipart, a continuación, POST es mutable. Esto parece poner el freno en la mayoría de las teorías que pueda pensar. (A menos que este comportamiento es un descuido.)

En resumen, puedo ver ninguna razón clara en Django para el objeto POST ser inmutable para multipart solicitudes no.

+0

Me he dado cuenta de toneladas de bordes ásperos como este en Django. Sin embargo, debe haber tenido sentido para alguien en algún momento. –

+2

Encontré esto en otra respuesta de pila: "Y debe ser inmutable para que pueda construirse de forma perezosa. La copia obliga a obtener todos los datos POST. Hasta la copia, puede que no se obtenga todo. Además, para un multiproceso Servidor WSGI para trabajar razonablemente bien, es útil si esto es inmutable " – Seaux

+0

@Seaux: vea mi punto # 4. –

5

actualización:

Gareth Rees estaba en lo cierto que el punto 1 & 3 no eran válidas en este caso. Aunque creo que los puntos 2 y 4 siguen siendo válidos, entonces dejaré las tesis aquí.

(me di cuenta de que el request.POST objeto tanto de la pirámide (Pilón) y Django es alguna forma de MultiDict. Así que tal vez es una práctica más común de hacer request.POST inmutable.)


que pueda 't hablan para los chicos de Django, aunque me parece que podía a causa de algunas de estas razones:

  1. performence. Los objetos inmutables son "más rápidos" que los mutables, ya que permiten optimizaciones sustanciales. Un objeto es inmutable significa que podemos asignarle espacio al tiempo de creación, y los requisitos de espacio no cambian. También tiene cosas como la eficiencia de la copia y la eficiencia de comparación debido a eso. Editar: este no es el caso para QueryDict como señaló Gareth Rees.
  2. En el caso de request.POST, parece que ninguna actividad en el lado del servidor debería modificar los datos de la solicitud. Y, por lo tanto, los objetos inmutables son más apropiados, por no mencionar que tienen una importante ventaja de rendimiento.
  3. Los objetos inmutables se pueden utilizar como dict llaves, que yo supongo podría ser muy útil en algún lugar de Django .. Editar: mi error, inmutable no implica directamente hashable; hashable objetos sin embargo, son típicamente inmutables también.
  4. Cuando pase alrededor de request.POST (especialmente para complementos de terceros y fuera), puede esperar que este objeto de solicitud del usuario permanezca sin cambios.

De alguna manera, estas razones también son respuestas genéricas a "inmutable vs mutable?" pregunta. Estoy seguro de que hay muchas más consideraciones de diseño que las anteriores en el caso Django.

+1

El último caso es realmente importante. Realmente se trata de seguridad. Esta es la razón por la cual Django proporciona 'sessions', que es una forma corta de obtener y modificar datos entre estados. – CppLearner

+2

Su punto (1) no puede ser la respuesta en este caso, porque 'POST' es un [objeto' QueryDict'] (https://github.com/django/django/blob/master/django/http/__init__ .py # L371), y estos objetos no obtienen ningún beneficio de rendimiento por ser inmutable. Y su punto (3) no puede ser la respuesta, porque los objetos 'QueryDict' no son hashables, por lo que no pueden usarse como claves del diccionario. –

+0

@GarethRees Gracias por señalar esto. De hecho, estaba equivocado. Actualicé mi respuesta para corregir esto. Debería haber prestado más atención a 'QueryDict' antes de responder. –

61

Si la petición fue el resultado de una presentación Django form, entonces es razonable para la POST ser immutable para asegurar la integridad de los datos entre la forma presentación y la validación del formulario . Sin embargo, si la solicitud fue no enviado a través de una presentación de Django form, entonces POST es mutable ya que no hay forma de validación.

Siempre se puede hacer algo como esto: (según @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: Supongo que el comentarista quiso hacer POST mutable, y el fragmento de código en esta respuesta ayudó. – ShreevatsaR

+0

Puede agregar una nueva clave, valor pero no puede cambiar los datos existentes. –

2

encontré esto en un comentario en la pila respuesta https://stackoverflow.com/a/2339963

y debe ser inmutable, de modo que pueda ser construido perezosamente. La copia obliga a obtener todos los datos POST. Hasta la copia, es posible que no se obtenga todo.Además, para que un servidor WSGI multiproceso funcione razonablemente bien, es útil si esto es inmutable

3

Me gusta que sea inmutable de forma predeterminada. Como se indicó, puede hacerlo mutable si lo necesita, pero debe ser explícito al respecto. Es como 'Sé que puedo hacer que mi forma depure una pesadilla, pero sé lo que estoy haciendo ahora'.

Cuestiones relacionadas