Cada vez más Python se convierte en una interesante herramienta para la nosotros los web developers.
Con frameworks como Django, Tornado, Flask , Bottle y otros uniéndose a los ya conocidos WebPy y Pyramid (ex Pylons) tenemos una gran cantidad de Frameworks para elegir.

Aunque Django es oficialmente el framework más famoso en el mundo de Python, Flask es quizá mi favorito para iniciarse en el desarrollo web.

Según sus autores:

“Flask es un microframework para Python basado en Werkzeug, Jinja 2 y buenas intenciones”

Werkzeug es una libreria WSGI que maneja básicamente los requests entre el cliente y el servidor
Jinja 2 es un lenguaje de templates para python inspirado en el utilizado por Django.

En este artículo vamos a ver como crear y estructurar una aplicación básica en Flask.
Hay muchos tutoriales sobre como lograr que tu aplicación de Flask muestre el típico “Hello World!” y por eso vamos a ir un paso más allá.

Al finalizar este ejercicio habremos visto como:

  1. organizo mis archivos
  2. genero un template básico con Jinja 2

Todo el código desarrollado puede ser encontrado en el repositorio de github para este proyecto.

requisitos:

  • Python básico
  • tener instalado y saber utilizar pip
  • tener instalado y saber utilizar virtualenv
  • hemos hecho el tutorial básico de Flask
  • HTML y CSS básicos

1. Estructurando mi proyecto

nota: Todos mis ejemplos sobre como trabajar comandos específicos serán para sistemas *nix, si trabajan en otro tipo de OS deberán hacerlo de la manera que este requiere.

la estructura básica que utilizo yo para mis proyectos es la siguiente (se que hay muchas maneras y es cuestión de gustos):



Proyecto
├── app
│   ├── static
│   │   ├── css
│   │   └── js
│   └── templates

para lograr esta estructura rápidamente escribimos en nuestra terminal


$ mkdir -p proyecto/app/{'static','templates'}
$ mkdir proyecto/app/static/{'css','js'}

Con esto ya tenemos organizada nuestra estructura de trabajo.

A continuación creamos nuestro entorno virtual y lo agregamos a .gitignore


$ virtualenv venv
$ echo 'venv' > .gitignore #este paso es solo necesario si van a trabajar con un repositorio git

Luego activamos el entorno virtual y utilizamos pip para instalar flask


$ source venv/bin/activate
$ pip install flask

En la carpeta principal del proyecto creamos un archivo run.py (este ejecutará el programa en local), y dentro de la carpeta app creamos un archivo __init__.py


$ touch run.py && touch app/__init__.py

Editamos el __init__.py que recién hemos creado y escribimos:


from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
	return 'El app funciona'

Aquí hemos instanciado en app una aplicación de Flask, y luego hemos creado para ella una ruta a la raíz del servidor (localhost en este caso) que renderice el texto que retorna la función.

A continuación generaremos nuestro iniciador de la aplicación en run.py de la siguiente manera:


from app import app
app.run(debug=True)

Estamos importando la instancia app que creamos en __init__.py y la estamos ejecutando con app.run
al pasarle debug=True estamos pidiendole a Flask que active el Debugger de Werkzeug, esto nos ayudará durante todo el proyecto a entender que es lo que está fallando cuando algo falla al darnos los Tracebacks de cada error.

Ahora para ejecutar la aplicación simplemente ejecutamos el archivo run.py de la siguiente forma:


$ python run.py

Deberíamos ver el servidor de flask arrancando.


* Running on http://127.0.0.1:5000/
* Restarting with reloader

Si vamos ahora en un navegador a http://localhost:5000/ deberíamos ver el mensaje que retornamos renderizado.

El servidor de Flask utiliza de manera predeterminada el puerto 5000 para ejecutar las aplicaciones.

2. Mi primer template

Hasta aquí no hemos hecho nada que no estuviese ya en los ejemplos básicos de Flask, así que en vez de renderizar un texto pasemos a renderizar páginas html más complejas.
Podríamos por supuesto pasar una cadena de texto que generase todo el HTML que necesitamos, pero es fácil darse cuenta de por qué esto sería poco práctico y acabaría con el sentido de estar utilizando un lenguaje para renderizar desde el backend.

Lo primero que haremos será crear un archivo que gestione todas nuestras vistas (rutas) para la aplicación.


$ touch app/views.py

Luego cambiaremos nuestro archivo __init__.py para que importe estas vistas en vez de procesarlas ahí mismo:


from flask import Flask

app = Flask(__name__)

from app import views #esta línea debe ir siempre al final para asegurarnos de que todo se importa en el orden adecuado

A continuación vamos a views.py, importaremos los metodos más comunes de flask y llamaremos a nuestro primer template (que aún no hemos creado).


from flask import request, redirect, render_template, url_for
from app import app

@app.route('/')
def index():
	return render_template('index.html')

Ahora debemos crear el template para index.html que hemos mencionado, pero vamos a hacerlo de la manera Jinja2.

Jinja2 permite generar un template de base para otros templates. En este caso estamos hablando de generar en un solo archivo html todo el código que se repetirá en muchas o todas las secciones que vayamos a crear. Lo más común aquí es generar el head del documento y los controles de navegación, así que hagamos eso.
Dentro de la carpeta templates creamos el archivo base.html y comenzamos a poblarlo


$ touch app/templates/base.html

  <!DOCTYPE html>
    {% if title %}
      {{title}}
    {% else %}
      Mi Primera App de Flask
    {% endif %}
      <nav>
        <ul>
	  <li><a href="#">Link 1</a></li>
	  <li><a href="#">Link 2</a></li>
	  <li><a href="#">Link 3</a></li>
        </ul>
      </nav>
      {% block content %}
      {% endblock %}
      <footer>
        {% block footer %}
        {% endblock %}
         @ Mi empresa
      </footer>

Aquí tenemos muchos elementos nuevos.
Primero veamos que Jinja2 tiene dos maneras de interactuar con nuestros documentos.

  • {{ }} nos permite imprimir variables que hayamos generado o pasado al template
  • {% %} nos permite realizar operaciones programáticas en los templates.

En el ejemplo hemos dicho al template que si la página para la que generará código tiene un título, este debe imprimirse, en caso contrario el título estandar será “Mi Primera App de Flask”.
Notese que todos los procesos lógicos en Jinja deben iniciarse y cerrarse, si esto no se realiza veremos como Werkzeug nos muestra un error muy claro que apunta a esto.

El segundo punto importante son los bloques. Jinja2 trabaja con elementos block que nos permiten unir distintos templates de manera dinámica. En este caso hemos generado un bloque content que colocará allí el contenido principal de los demás templates.
Del mismo modo tenemos un bloque footer que permitirá personalizar los footers según querramos.

Nos toca generar el template para index.html


$ touch app/templates/index.html

y lo rellenamos:


{% extends "base.html" %}

{% block content %}
Este es el contenido de mi Index, en un futuro contendrá la infromación que quiero mostrar cuando los usuarios hayan hecho login.


{% endblock %}
Esto no está siendo renderizado, o si???


{% block footer %}

Este es el footer de mi index, no dice nada util pero podría!!!

{% endblock %}

Aquí tenemos dos elementos característicos de Jinja2.
Primero vemos como le decimos a este template que extiende al template base. Esto quiere decir que el código que coloquemos en este template debe estar dentro de los bloques definidos en el template que extiende. Si colocamos cualquier cosa fuera de estos bloques NO sera renderizado.

Vemos que hemos colocado tres párrafos distintos para realizar esta prueba. Uno dentro de cada bloque y uno fuera.

Volvemos a ejecutar nuestro archivo run.py y nos dirigimos a http://localhost:5000/ y deberíamos ver nuestra página perfectamente renderizada (con excepción del párrafo que dejamos fuera de los bloques definidos).

Por último finalizaremos este artículo viendo como pasar variables a los templates (como el del título).

Para mostrarles las dos maneras de hacerlo vamos a agregar una pequeña línea en nuestro bloque content y de paso les muestro como manejar un for loop en jinja2.

Agregamos lo siguiente:


  <h4>Esta es una lista de cosas que me gusta</h4>
  <ul>{% for item in cosas %}
	<li>{{item}}</li>
  </ul>
  {% endfor %}

Este código muestra como trabajamos de manera muy similar a python (excepto por el endfor final). La variable cosas no ha sido creada y lo haremos en un momento (obviamente debe ser un elemento iterable).
Antes de mostrarles como hacer esto desde la vista misma vamos a ver como definir variables en los templates.

Agregamos la siguiente línea debajo de donde extendemos el template:


{% set title ='Titulo bamba' %}

Esto definirá la variable título del template y reemplazará según lo definimos en base.html

Ahora nos movemos a views.py y lo modificamos de la siguiente manera:




@app.route('/')
def index():
    return render_template(
        'index.html',
        cosas=['RPG', 'Python', 'Juegos de mesa', 'Cthulhu', 'etc']
    )

Como ven solo hemos definido una variable como parámetro de la función render_template y hemos reestructurado el código para que siga los requisitos de PEP8

Si guardan los cambios y refrescan sus browsers verán como ahora todo se renderiza como esperábamos.
Con esto terminamos la primera parte del artículo.
En esta parte hemos visto cómo:

  • Estructurar nuestros archivos y carpetas para un proyecto pequeño/mediano
  • Crear un archivo de arranque para el servidor separado de la aplicación en sí
  • Renderizar templates de jinja2, creando templates base con distintas secciones y como extenderlos
  • Condicionales y for loops en jinja2
  • Definir variables en el template o pasarlas como parametros de la vista

Terminamos

Con esto terminamos esta introducción a Flask y sus componentes básicos. Espero que les haya servido para dar un vistazo a lo sencillo que es trabajar con Flask.

El código de este proyecto lopueden encontrar en github.