Aplicaciones Web sencillas con Python (y 2)

Plantillas
 
En el último ejemplo comenzamos a utilizar HTML, que, al fin y al cabo, es el medio por el cual presentaremos la información en el navegador. El problema que tenemos es que se mezcla el código de Python y de HTML, y
a la hora de depurar o realizar modificaciones, se vuelve enfarragoso y complejo. La forma ideal de trabajar sería separando la presentación (HTML) del código que procesa la información (Python). Por un lado estarían las etiquetas HTML que ponen la información, y por otro el código Python que accede a la base de datos y la prepara en estructuras de datos.
 
WebPy posee la característica de utilizar plantillas, que son directivas especiales embebidas en un código HTML, y que permiten conmutar valores que se pasan desde la capa de negocio o interactuar directamente con código Python.

Para estructurar nuestro código, vamos a crear un directorio donde se van a guardar las plantillas que vamos a necesitar. En nuestro caso la llamaremos plantillas. Dentro de este directorio crearemos un fichero llamado (por
ejemplo) plantilla.html, y cuyo contenido será el siguiente:

$def with (nombre, apellido)
<HTML>
   <HEAD></HEAD>
   <BODY>
   $if (nombre!='' and apellido!=''):
      <H1>Hola, $nombre $apellido</H1>
   $else:
      <b>ERROR:</b> No ha facilitado el nombre y el apellido
   </BODY>
</HTML>
 
La primera línea
 
$def with (nombre, apellido)
 
debe ser la primera de la plantilla, y se encarga de recoger los parámetros enviados desde el código de negocio, los cuales serán presentados en la página HTML.

A continuación se crea el código HTML. Cuando es necesario presentar la información, hemos creado una estructura de control if para comprobar los datos pasados. En nuestro caso comprobamos si nombre y apellido contienen datos, en cuyo caso imprimirá en un título el mensaje “Hola, “ seguido del nombre y del apellido. Si uno de los dos datos no se ha facilitado, entonces (else) se mostrará un mensaje de error.

Ha de notarse que anteponiendo el símbolo $ (dólar) a una línea en Python, esta se procesará como código Python. Asimismo, este símbolo también se utiliza dentro del HTML para sustituir una variable por su valor. Esta plantilla, por sí misma no hace nada, debe ser asociada a la capa de negocio. Para ello crearemos el código en un fichero situado fuera del directorio plantillas, justo en el nivel anterior. El código será el siguiente:


import web
 
urls = (
   '/hola', 'Saludo'
)
 
render = web.template.render('plantillas')
 
app = web.application(urls, globals())
 
class Saludo:
   def GET(self):
      data = web.input()
      nombre = data.nombre if 'nombre' in data else ''
      apellido = data.apellido if 'apellido' in data else ''
      return render.plantilla(nombre, apellido)
 
if __name__ == "__main__":
   app.run()
 
El objeto render apuntará al directorio donde se encuentran nuestras plantillas, creando internamente un objeto por cada plantilla encontrada.
 
En el método GET de la clase Saludo, hemos reforzado el código (a prueba de errores) en cuanto a los parámetros. Si se pasa el parámetro especificado, recogerá su valor. Si no se pasa, le asignará una cadena vacía. Los parámetros pasados están en formato diccionario, por lo que es posible averiguar si el parámetro (clave) está dentro del mismo (‘clave’ in diccionario).

Por último, se retorna lo generado por la plantilla. Para ello se invoca a la plantilla:

render.plantilla(nombre, apellido)
 
Como se comentó anteriormente, internamente, WebPy toma las plantillas dentro del directorio al que apuntaba, y generará un objeto accesible por cada una de ellas. A la plantilla le facilitará los parámetros nombre y apellido, que serán recogidos por la primera línea de éste ($def with).
 
Un ejemplo más complejo
 
Los ejemplos anteriores han sido muy básicos. Vamos a ver un poco más a fondo cómo podemos aprovechar todo lo anterior. Imaginemos que queremos hacer una consulta a un catálogo de productos. Esta consulta puede ser general (muestra todos los productos), o bien específica (muestra un producto determinado). La solución pasaría por implementar un acceso a base de datos. Pero para no extender demasiado este artículo, vamos a tenerlo completamente en memoria.
 
El código de negocio quedaría como sigue:

import web
 
urls = (
   '/ejemplo', 'Consulta'
)
 
render = web.template.render('plantillas')
 
app = web.application(urls, globals())
 
class Consulta:
   def GET(self):
      criterio = web.input()
 
      # Tuplas de diccionaris con datos de consulta.
      # Puede ser una carga de datos de una bbdd
      datos = (
         {'producto':'Tornillo', 'precio':0.45, 'marca':'Acme'},
         {'producto':'Tuerca', 'precio':0.55, 'marca':'Solme'},
         {'producto':'Clavo', 'precio':0.30, 'marca':'Calme'},
         {'producto':'Remache', 'precio':0.60, 'marca':'Acme'},
         {'producto':'Clavija', 'precio':0.95, 'marca':'Acme'},
         {'producto':'Grapa', 'precio':0.25, 'marca':'Tecme'}
      )
 
      registro=''
 
      if criterio:
         for i in range(0,len(datos)):
            if datos[i]['producto'] == criterio.producto:
               registro = datos[i]
               break
 
      if registro =='':
         registro = datos
 
      return render.productos(registro)
 
if __name__ == "__main__":
   app.run()
 
La llamada a la página puede hacerse sin parámetros (mostraría todos los productos), o bien pasando el parámetro producto, especificando cuál queremos consultar.

En ambos casos, a la hora de invocar a la plantilla, se pasaría la lista de productos o un único producto, que se almacena en la variable registro.
 

El código de la plantilla (productos.html) sería el siguiente:
 
$def with (registro)
<HTML>
   <HEAD></HEAD>
   <BODY>
   <TABLE BORDER='1'><TR BGCOLOR='#AAAAFF'>
   <TD><B>PRODUCTO<B></TD>
   <TD><B>PRECIO<B></TD>
   <TD><B>MARCA<B></TD></TR>
   $if 'producto' in registro:
      <TR>
      $for i in range(0,len(registro)):
         <TD> $registro.values()[i] </TD>
      </TR>
 
   $else:
      $for i in registro:
         <TR>
         <TD> $i['producto'] </TD>
         <TD> $i['precio'] </TD>
         <TD> $i['marca'] </TD>
         </TR>
 
   </TABLE>
   </BODY> 
</HTML>
 
En el caso de que se pase un único registro (la consulta se hizo por un único producto), éste será en sí un diccionario, por lo que al consultar si tiene una clave llamada producto, retornará el valor True. En tal caso, la función len() retorna el número de pares clave/valor del diccionario. Conociendo este valor, se recorre cada campo del diccionario en el bucle for y se extrae su valor, visualizándolo en una columna.

En el caso de pasar el catálogo completo, la función len() retornaría el número de filas (diccionarios) que contiene la lista. El acceso a la lista debe realizarse mediante un iterador (i), el cual recoge, uno a uno, cada fila (diccionario). El valor se extrae invocando el nombre de su clave. 
 
 
Conclusiones
Este breve tutorial cubre los aspectos más básicos, pero, a la vez, más potentes y flexibles, para comenzar a desarrollar aplicaciones Web mediante Python. A partir de las nociones vistas anteriormente, podremos empezar a
desarrollar complejas web dinámicas de una forma sencilla y eficaz.


 
Referencias
Lenguaje Python | Página oficial
Módulo mod_wsgi | Página oficial
WebPy | Página oficial
Apache | Página oficial
© commandcat
Maira Gall