2012-09-05 18 views
18

Este es un problema que se me ocurrió mientras trabajaba en un proyecto de Django. Se trata de la validación de formularios.Python: Evite la evaluación de cortocircuitos

En Django, cuando tiene un formulario enviado, puede llamar al is_valid() en el objeto de formulario correspondiente para activar la validación y devolver un valor booleano. Así que, por lo general tiene código de esa manera dentro de sus funciones de vista:

if form.is_valid(): 
    # code to save the form data 

is_valid() no sólo valida los datos del formulario, pero también añade mensajes de error para el objeto de formulario que luego se pueden mostrar al usuario.

En una página utilizo dos formularios juntos y también deseo que los datos se guarden solo si ambos formularios contienen datos válidos. Eso significa que tengo que llamar a is_valid() en ambos formularios antes de ejecutar el código para guardar los datos. La forma más obvia:

if form1.is_valid() and form2.is_valid(): 
    # ... 

no funcionará debido a la evaluación de cortocircuito de los operadores lógicos. Si form1 no es válido, form2 no se evaluará y faltarán sus mensajes de error.

Eso es solo un ejemplo. Por lo que yo sé, no hay una alternativa codiciosa para and/or como en otros idiomas (es decir, Smalltalk). Puedo imaginarme que ese problema ocurre bajo diferentes circunstancias (y no solo en Python). Las soluciones en las que pude pensar son torpes (ns anidados, asignando los valores de retorno a variables locales y usándolos en la sentencia if). Me gustaría saber la manera pitónica de resolver este tipo de problemas.

¡Gracias de antemano!

Respuesta

27

¿Qué tal algo como:

if all([form1.is_valid(), form2.is_valid()]): 
    ... 

En un caso general, una lista-comprensión podría ser utilizado para que los resultados se calculan por adelantado (en contraposición a una expresión del generador que se utiliza comúnmente en este contexto) . ej .:

if all([ form.is_valid() for form in (form1,form2) ]) 

Esto escalar muy bien a un número arbitrario de condiciones, así ... El único inconveniente es que todos ellos necesitan ser conectados por "and" en contraposición a if foo and bar or baz: ....

(para un cortocircuito or, puede usar any en lugar de all).

+0

Exactamente lo que busqué. ¡Gracias! – j0ker

+2

Me tomó unos segundos llegar a esto. Es un caso de esquina que no había considerado antes (a menudo trabajo en Fortran, lo que no garantiza el cortocircuito, pero lo permite) y siempre trato de encontrar la forma de asegurarme de que mis expresiones estén en cortocircuito. Pensar en esto fue un poco retrógado para mí :). – mgilson

+0

Sí, el 'todo' es el camino a seguir aquí, pero ¿dónde usaste listas de comprensión? Solo veo una lista simple en tu ejemplo. – rantanplan

16

Puede simplemente usar el operador binario &, que hará un circuito lógico sin cortocircuito Y en bools.

if form1.is_valid() & form2.is_valid(): 
    ... 
+3

Más específicamente, hará un 'y' en bits en enteros. Como los bools se derivan de enteros con 'True == 1' y' False == 0', esto funciona. No (necesariamente) funcionará para otros tipos o para funciones que devuelven cosas que no son booleanas. Aún así, es una buena herramienta para tener alrededor (+1) – mgilson

+1

Definitivamente más simple que la solución de mgilson. ¡Gracias por eso! El otro podría ser más útil para otras personas que leen el código. Aquí, supongo que podrías pensar que confundí 'y' y' & '. – j0ker

+0

@mgilson La función 'all' también fue la primera solución que se me vino a la cabeza (la usaría exactamente por la razón que mencionó j0ker), pero descubrí la pregunta para esa respuesta (+1, btw) :-) – sloth

Cuestiones relacionadas