2010-05-21 10 views
5

Se ha mencionado en otras respuestas sobre cómo obtener el mismo código para el def get(self) y el def post(self) para cualquier solicitud dada. Me preguntaba que utilizan técnicas de la gente, yo estaba pensando:Ejecutando el mismo código para get (self) como post (auto)

class ListSubs(webapp.RequestHandler): 
    def get(self): 
     self._run() 

    def post(self): 
     self._run() 

    def _run(self): 
     self.response.out.write("This works nicely!") 

Respuesta

11

Yo sugeriría tanto por razones teóricas y prácticas por qué el enfoque que está usando (refactorización el código común a un método separado y decir que es tanto de entrada y obtener métodos) es superior a la alternativa aparentemente más simple de simplemente hacer que uno de esos dos métodos llame al otro.

Desde un punto de vista teórico, "el método A delega completamente al método B" implica una noción de "primacía" o "asimetría" - una decisión de diseño que, en adelante, cualquier cambio que pueda aplicarse a B inevitablemente intrínsecamente se aplican a A también; que A pueda ser ligeramente personalizado en el futuro con respecto a B (agregando algún código adicional antes y/o después de la llamada de A a B) pero nunca al revés. Cuando no hay ninguna razón para esperar tal primacía, es una mala decisión de codificación insertar esa noción en su código. Al hacer que tanto A como B invoquen el método privado común C, se evita romper la simetría.

Algunas personas no están contentas con los argumentos teóricos y prefieren las pragmáticas: afortunadamente, en este caso, lo teórico se traduce directamente a la bonita pragmática. De nuevo, es un problema de evolución futura del código: tener llamadas A y B de C deja todos los grados de libertad necesarios para realizar pequeñas personalizaciones (agregar código antes y/o después de la llamada a C) a cualquiera, ambos o ninguno de A y B. Como no sabes qué partes de esta flexibilidad necesitarás, y el costo en términos de simplicidad es minúsculo, tomar la ruta simple y flexible es altamente pragmático y aconsejable.

Un último punto pragmática (aplicando a una u otra opción): Cada vez que haya un patrón como:

def amethod(self): 
    return cmethod(self) 

que está por lo general (modestamente) mejor reformular esto como

amethod = cmethod 

Este evita un nivel innecesario de anidamiento de llamadas (el plano es mejor que el anidado). Por lo tanto, la clase podría ser útil codificado:

class ListSubs(webapp.RequestHandler): 

    def _run(self): 
     self.response.out.write("This works even better!") 

    get = post = _run 

No es gran cosa, y que tendrá que refactorizar volver a la forma original de "anidado", siempre y cuando no es necesario aplicar ajustes antes o después de la llamada anidada (desde get hasta _run, etc.) o necesita otros ajustes en la depuración (por ejemplo, establezca un punto de interrupción en su depurador en post pero sin tener el punto de interrupción en get, etc.), pero una pequeña simplificación para aquellos tiempos en que sea factible.

+1

¡Gracias, no es una lección que olvidaré en mucho tiempo! –

2

Refactorizando el código que hace el trabajo en su propia función/método es el método correcto.

+0

Ok, ¿así es básicamente lo que hice arriba? –

+1

Eso es correcto. –

2

He utilizado este:

class ListSubs(webapp.RequestHandler): 
    def post(self): 
     self.response.out.write("This works nicely!") 
    def get(self): 
     self.post() 
+2

Mientras esto funciona, incide ligeramente en el Principio de asombro mínimo. –

1

Una cosa que no he visto en las respuestas, que incluiré, es por qué no deberías hacer esto. Es un principio bastante común que un HTTP GET cambiando datos en el servidor es una mala idea. Cambiar el estado del servidor generalmente debe ocurrir a través de POST. Como resultado, cada URL que se usa para GET y POST debe tener acciones específicas que difieren según el tipo de solicitud. El w3c tiene un bonito overview of when to use GET vs. POST también.

Tiendo a pensar en GET y POST como un getter y un setter. POST s cambian los datos, y GET s obtienen datos. Como resultado, una búsqueda simple puede usar GET durante todo el día, pero cuando guarde una configuración en el servidor, un POST está en orden.

Por ejemplo, supongamos que tiene una URL para una publicación en su blog (example.com/blog/post-vs-get/). Luego puede usar get() para obtener la publicación del blog y presentarla en la pantalla con un buen formulario de comentarios. En este ejemplo, mi formulario de comentario va a POST de nuevo a la misma URL, llamando al método post(), que puede procesar el formulario y luego devolver la misma página representada.

class ListSubs(webapp.RequestHandler): 
    def post(self): 
     comment = cgi.escape(self.request.get('comment')) 
     ## Do magic with our comment. 
     self.get() ## Go off and return the rendered page. 
    def get(self): 
     ## Get the blog post out of the data store and render a page. 
     self.response.out.write("""<html> 
       <body> 
       <p>My awesome blog post!</p> 
       <form method="post"> 
        <h1>Comment</h1> 
        <textarea name="comment" rows="3" cols="60"></textarea> 
        <input type="submit" value="Comment"> 
       </form> 
       </body> 
      </html>""") 

Esto proporciona una clara división de trabajo entre la representación de la página y el procesamiento de los datos POST. Esto también evita que su código ejecute una validación y/o procesamiento innecesarios en una solicitud sin datos. En mi opinión, esta separación de funciones también facilita la depuración y el mantenimiento del código.

+0

En una nota aparte, probablemente deba hacer una redirección después del POST para evitar que las personas refresquen accidentalmente la página y la publiquen nuevamente. –

Cuestiones relacionadas