Validación Personalizada de Formularios en Tornado

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>

Etiquetas: Tornado Python ValidaciónFormularios HTML WebDevelopment

Publicado el 7-31 06:04