Manejo de rutas en Flask

Publicado por Andrea Navarro en

En este artículo veremos el sistema de ruteo de Flask y como asociar rutas con funciones. Veremos como manejar y validar variables dentro de las rutas y utilizarlas dentro de las funciones. Finalmente veremos como utilizar el método de construcción automática de URL.

Flask hace uso de la librería Werkzeug para manejar el ruteo de sus aplicaciones. Werkzeug es una de las bibliotecas de aplicaciones web WSGI más utilizadas que permite la creación sencilla de endpoint y la asociación de funciones a los mismos.

Asociar rutas

Para asociar una ruta específica con una función Flask hace uso del decorador route. Este puede utilizarse a partir de la clase de Flask o desde un Blueprint. Este decorador permite disparar una función cuando el servidor reciba una solicitud que coincida con un patrón de URL.

from flask import Flask
app = Flask(__name__)

@app.route('/')
def saludo():
    return 'Hola!'

En este primer ejemplo el decorador route se genera a partir de la instanciación de la clase Flask. La URL definida es la raíz y la función asociada es saludo. Para que se ejecute debemos realizar una solicitud, por ejemplo desde un navegador, a la ruta raíz de nuestra aplicación. En el caso que el servidor este corriendo en el puerto 5000 de manera local la solicitud en el navegador sería la siguiente:

http://127.0.0.1:5000/

Esta ruta puede tener tantos niveles como sea necesario

@app.route('/usuario/saludar')
def saludo():
    return 'Hola!'

En este caso la solicitud necesaria para acceder a la función saludo sería la siguiente:

http://127.0.0.1:5000/usuario/saludar

Es posible asociar una función a múltiples rutas. Cuando se realice una solicitud se verificará que la ruta coincida con alguna de las asociadas a la función.

@app.route('/usuario/saludo')
@app.route('/usuario/saludar')
def saludo():
    return 'Hola!'

Será posible en este caso acceder a la función saludo a partir de cualquiera de las dos solicitudes

http://127.0.0.1:5000/usuario/saludar
http://127.0.0.1:5000/usuario/saludo

Variables

En muchos casos las rutas de acceso a las funciones de nuestra aplicación no serán estáticas sino que tendrán secciones de la misma que serán variables. Estas variables pueden especificarse utilizando el formato <nombre_variable>.

@app.route('/usuario/saludo/<nombre>')
def saludo(nombre):
    return 'Hola '+ nombre

En este ejemplo se accederá a la función saludo para cualquiera de las siguientes solicitudes.

http://127.0.0.1:5000/usuario/saludo/Maria
http://127.0.0.1:5000/usuario/saludo/Pedro
http://127.0.0.1:5000/usuario/saludo/Gonzalo

En cada uno de estos casos el parámetro nombre definido en la función saludo tomará el valor de la ruta que ocupa la variable con el mismo nombre. Para que este valor sea asignado el nombre de la variable de la ruta expresado entre <> y el nombre del parámetro de la función tienen que ser idénticos.

En el caso que una variable sea opcional es necesario dar un valor por defecto al parámetro de la función.

@app.route('/usuario/saludo/')
@app.route('/usuario/saludo/<nombre>')
def saludo(nombre = None):
    if nombre is None:
       return 'Hola!'
    else:
       return 'Hola '+ nombre +'!'

En este caso si la ruta no contiene una variable después de saludo al parámetro nombre se le asignará un valor None y la función devolverá un saludo genérico. Si por otra parte la ruta termina con una variable esta será asignada como valor del parámetro nombre de la función y está devolverá un saludo utilizando el nombre del usuario

Convertidores

Un caso muy común de uso de variables en rutas es el uso de ID para identificar elementos inequívocamente que pueden estar almacenados en archivos, bases de datos o APIs. Para evitar errores es necesario verificar que la variable que se está pasando en un número entero y no una cadena de caracteres. Podemos lograr esto utilizando los convertidores de forma <convertidor:nombre-variable>

@app.route('/usuario/ver/<int:id>')
def ver(id):
    // Buscar usuario por id
    return 'Hola '+ usuario.nombre +'!'

Para este caso las siguientes solicitudes permitirán acceder a la función ver.

http://127.0.0.1:5000/usuario/ver/23
http://127.0.0.1:5000/usuario/ver/4
http://127.0.0.1:5000/usuario/ver/1512

Sin embargo, las solicitudes listadas a continuación no se asociarán a la función ver.

http://127.0.0.1:5000/usuario/ver/Pablo
http://127.0.0.1:5000/usuario/ver/12.5
http://127.0.0.1:5000/usuario/ver/usuario/12

A continuación se detallan los tipos de convertidores aceptados:

stringCadenas de caracteres
intEnteros positivos
floatNúmeros de punto flotante positivos
pathCadenas de caracteres que permiten ‘/’
uuidCadenas de caracteres UUID

Métodos HTTP

Por defecto todas la rutas responden solamente al método GET. Si es necesario que la ruta acceda a otros métodos es necesario especificarlo. Por ejemplo, si una ruta va a ser accedida a través de el envío de un formulario por POST debemos agregar este método a los aceptados por la ruta.

@app.route('/usuario/crear', methods=['GET', 'POST'])
def crear_usuario():
    //Implementación de creación de usuario

Estas funciones pueden devolver como resultado cadena de caracteres, diccionarios, o cualquier otro tipo de estructuras de datos. Sin embargo Flask tiene implementado el motor de templates Jinja con el que es posible renderizar templates y devolver vistas que pueden ser mostradas en el navegador.

Construcción de URL de rutas

Flask permite la construcción automática de URL a partir de la función asociada y los parámetros utilizando la función url_for. Para el siguiente ejemplo de ruta:

@app.route('/usuario/saludar')
def saludar():
    return 'Hola!

Podremos construir la URL correspondiente utilizando la función url_for ya sea en la implementación de otra función o dentro de un template de la siguiente manera:

  url_for('saludar')

Está función dará como resultado:

/usuario/saludar

En el caso de que la ruta tenga una o más variables es necesario pasarlas como parámetro.

@app.route('/usuario/saludar/<nombre>')
def saludar(nombre):
    return 'Hola '+ nombre +'!'

Al contener una variable pasamos el valor del parámetro

url_for('saludar', nombre='Marta')

Lo que dará como resultado:

/usuario/saludar/Marta

El uso de está función para la construcción de URL tiene algunas ventajas con respecto al uso de las rutas de manera directa. La primera de estas ventajas sucede cuando es necesario cambiar la ruta de una función y está ya ha sido referenciada en diferentes partes de nuestra aplicación. Si las rutas han sido configuradas manualmente entonces debemos buscarlas y modificarlas individualmente mientras que si utilizamos la función url_for solo será necesario modificar la URL una sola vez. Otra ventaja es que esta función utiliza siempre path absolutos por lo que no surgirán problemas con path relativos.

Archivos estáticos

La función url_for permite generar URL para los archivos estáticos requeridos en una aplicación web. Para hacerlo es necesario que dichos archivos se encuentren dentro de una carpeta llamada static dentro de la aplicación.

url_for('static', filename='estilo.css')
url_for('static', filename='img/imagenA.css')

Siempre que estos archivos se encuentren dentro de la carpeta static Flask contruirá la URL correspondiente.


En este artículo hemos visto el sistema de ruteo de Flask, las configuraciones más comunes y cómo generar URL automáticamente. Espero que les sea de utilidad.


¿Preguntas? ¿Comentarios?

Si tenés dudas, o querés dejarnos tus comentarios y consultas, sumate al grupo de Telegram de la comunidad JuncoTIC!
¡Te esperamos!

Categorías: Programación

Andrea Navarro

- Ingeniera en Informática - Docente universitaria - Investigadora