Implemantación de Validación de Formularios
En aplicaciones web, la validación manual de parámetros mediante self.get_argument() genera código repetitvio. La solución es implementar un sistema de validación personalizado:
Validación Básica con Expresiones Regulares
import re
import tornado.web
class FormularioSimple:
def __init__(self):
self.dominio = "(.*)"
self.direccion_ip = r"(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"
self.puerto = r"(\d+)"
self.telefono = r"^1[3-8][0-9]\d{8}$"
def verificar(self, handler):
valido = True
valores = {}
for campo, patron in self.__dict__.items():
entrada = handler.get_argument(campo)
valores[campo] = entrada
if not re.match(patron, entrada):
valido = False
return valido, valores
class ManejadorPrincipal(tornado.web.RequestHandler):
def post(self):
formulario = FormularioSimple()
resultado, datos = formulario.verificar(self)
estado = 1 if resultado else 0
self.render("vista.html", estado=estado)
Refactorización con Herencia
Para múltiples formularios, se implementa una clase base:
class FormularioBase:
def verificar(self, handler):
valido = True
datos = {}
for campo, patron in self.__dict__.items():
entrada = handler.get_argument(campo)
datos[campo] = entrada
if not re.match(patron, entrada):
valido = False
return valido, datos
class FormularioIP(FormularioBase):
def __init__(self):
self.direccion_ip = r"(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"
Validación con Mensajes Personalizados
class CampoIP:
PATRON = r"(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"
def __init__(self, errores=None, requerido=True):
self.errores = errores or {}
self.requerido = requerido
self.valor = None
self.error = None
self.valido = False
def validar(self, nombre, entrada):
if not self.requerido:
self.valido = True
self.valor = entrada
else:
if not entrada.strip():
self.error = self.errores.get("requerido", f"{nombre} es requerido")
else:
if re.match(self.PATRON, entrada):
self.valido = True
self.valor = entrada
else:
self.error = self.errores.get("valido", f"{nombre} inválido")
class FormularioComplejo:
def __init__(self):
self.direccion_ip = CampoIP(
errores={"requerido": "Campo obligatorio", "valido": "Formato incorrecto"}
)
Validación de Checkboxes y Archivos
class CampoCheckbox:
def validar(self, nombre, entrada):
if self.requerido and not entrada:
self.error = f"{nombre} es requerido"
else:
self.valido = True
self.valor = entrada
class CampoArchivo:
PATRON = r"^(\w+\.(pdf|mp3|py|jpg))$"
def validar(self, nombre, archivos):
if self.requerido and not archivos:
self.error = f"{nombre} es requerido"
else:
for archivo in archivos:
if not re.match(self.PATRON, archivo):
self.error = f"{nombre} inválido"
return
self.valido = True
self.valor = archivos
Implemantación HTML
<form action="/endpoint" method="post" enctype="multipart/form-data">
<input type="text" name="direccion_ip" placeholder="IP">
<input type="checkbox" name="opciones" value="1"> Opción 1
<input type="file" name="archivos" multiple>
<input type="submit" value="Enviar">
{% if estado == 0 %}
<p class="error">{{ mensaje_error }}</p>
{% end %}
</form>