viernes, 19 de junio de 2020

Flask 2. Enrutamiento y parámetros URL

File:Url-structure.png - Wikimedia Commons


Enrutamiento y parámetros URL


Rutas Estáticas.                         



En el post anterior vimos como Flask asocia una dirección de internet, una url, con un método de nuestra aplicación. Esto lo conseguimos añadiendo el decorador "route" a la función que queremos que se ejecute cuando se llame a esa página.

Si recuerdas creamos el siguiente código dentro de nuestro programa index.py:

@app.route("/")
def hola_mundo():
    return "Hola Mundo"

Por norma, a las funciones asociadas a una URL se le denominan "Vistas".

La vista anterior lo que hace es que cuando nosotros ejecutemos nuestro programa, el servidor nos llevará a nuestra pagina principal y nos imprimirá en la pantalla del navegador un "Hola Mundo".

Bien, vamos a añadir una nueva vista a nuestro proyecto, por ejemplo, algo que suele estar en cualquier pagina web, un "acerca de". Le diremos que cuando alguien entre en nuestra página web a la dirección:

127.0.0.1:5000/acerca_de/

Le muestre un texto como "Pagina editada por Perico Perez". Y como se hace esto, muy fácil, igual que lo anterior.

@app.route("/acerca_de/"):
def acercade():
    return "Pagina editada por Perico Perez"


Esto es lo que conseguimos.




Pero, ¿Que pasa si por ejemplo nos confundimos y tecleamos 127.0.0.1:5000/acercade?

Pues que tenemos un estupendo error (404) porque no es ninguno de los nombres que hemos definido en las vistas (hasta ahora tenemos solo definimos "/" y  "/acerca_de/")


Si quieres personalizarlo y decir a quien entre, que esa página no existe utilizamos el decorador
@app.errorhandler(404)

Por ejemplo si añadimos esto:

@app.errorhandler(404)
def pagina_no_encontrada(error):
    # Aqui hay que poner un parámetro a la función porque el decorador se lo pasa.
    return 'Pues no he encontrado la página....', 404

y repetimos lo de antes, ahora habremos personalizado el error.


Nota aclaratoria sobre acabar las URLs de las vistas con el carácter ‘/’ o no hacerlo

Al definir una URL acabada con el carácter ‘/’, por ejemplo "/acerca_de/", si el usuario accede a esa URL sin dicho carácter, Flask lo redirigirá a la URL acabada en ‘/’. En cambio, si la URL se define sin acabar en ‘/’ y el usuario accede indicando la ‘/’ al final, Flask dará un error HTTP 404, con lo cual es mejor ponerla siempre.


Rutas Dinámicas.                                 


    Hasta ahora las vistas o páginas que hemos creado solo mostraban un texto, eran muy estáticas, no hacían nada más. Esto no es lo normal en un proyecto, necesitamos poder introducir parámetros o lo que viene a ser lo mismo, contenido dinámico para darles un poco de alegría y que sean más funcionales.

Antes de continuar aclarar dos cosas:

    1º) La forma de que podamos introducir un parámetro en la url será poniendo:

                                /<parametro>/    
   
 en la vista que creemos.

    2º) Por defecto todo los parámetros que metamos a través de una página web se considerarán como que fueran del tipo string, como una cadena de texto vamos, con lo que ojo si queremos introducir valores numéricos para hacer cálculos. En este caso tenemos que decirle al programa que el string nos lo convierta en un número entero con la instrucción "int"

                            /<int:parametro>/

Luego ponemos un ejemplo.


Vamos a verlo con uno o dos ejemplos sencillos. Imaginemos que hemos creado una pagina web y queremos personalizar la bienvenida en función del nombre que mandemos a la url, y ya de paso sino introducimos nada que ponga otra cosa. ¿como haríamos esto en Flask? Podríamos hacer los siguiente, escribo el código y luego lo comento. Como estamos al comienzo escribiré de nuevo todo el programa y no solo las vistas:




  • En la línea 1 importamos la biblioteca.
  • En la 2 creamos la aplicación.
  • En la 4 construimos una vista para cuando se cargue la página de inicio, ya que sino ponemos una nos saldría al ejecutar el programa un error al no localizarse la vista.
  • linea 8, con el decorador construimos una vista por si solo llamamos a la url con /hola
  • linea 9, con el decorador construimos una vista por si pasamos el nombre del usuario. /hola/pepito
  • linea 10, construimos la función bienvenida y le decimos que por defecto tendrá un parámetro llamado nombre, que tendrá por defecto el valor None (nada), pero ahí está. Con esto ¿qué conseguimos? Pues una cosa importante, si escribimos la url:
                                                                    /hola 

         y no le pasamos ningún argumento, la función no nos dará error puesto que aunque le hemos puesto que la función requiere por fuerza un argumento, este ya existe, tiene un parámetro con un valor por defecto, aunque sea ninguno. Ahora bien si la vista ponemos:

                                                                 /hola/pepito

        también funcionará ya que el parámetro por defecto se anula y el parámetro "nombre" coje el valor que le pasamos, en este caso Pepito.
  • En la linea 11 creamos una condición que viene a decir que si nombre existe, entendiendo por existir que tenga algún valor (recuerda que None es como si no existiera ya que tiene un valor nulo o cero y por tanto dará False) devuelva "Bienvenido a nuestra web" más el nombre, y en cualquier otro caso "Hola usuario anónimo".

Dos cosas. La primera en python "if nombre:" es la forma fina y corta de decir "if nombre==True:" y la segunda para mostrar el nombre he utilizado un texto con formato para insertar el valor de la variable en el texto a mostrar.

Gráficamente:

Ejecutamos la aplicación con el nombre que hayas utilizado para el ejemplo, en mi caso rutas.py con:

$ python rutas.py

y si no ponemos el parámetro veremos:


y  si lo ponemos, es decir tecleamos en la barra de direcciones "127.0.0.1:5000/hola/pepito" aparecerá:




De forma rápida construimos otro ejemplo, una vista en el que introduciendo dos números en la url nos devuelva la suma:



En la vista le decimos al programa que los números (num1 y num2) nos los pase al programa como dos números enteros para poder sumarlos y de la misma forma el resultado lo retornamos convertido en string para lo que usamos el método str de python. Si solo pones return num1 + num2 y lo ejecutas Flask te dirá básicamente que no acepta retornar un número entero por pantalla, solo texto.



Comentar que aparte de <int:loquesea> también se pueden utilizar los siguientes comandos para modificar el tipo de parámetros que introducimos en la Url:

  • string: Acepta cualquier texto sin barras (por defecto). Si no ponemos nada en el parámetro como ya dijimos lo considera como un string, una cadena de texto.
  • int: para convertirlo en enteros
  • float: para  valores reales, con decimales.
  • path: Acepta cadena de caracteres con barras

Construcción de Rutas a partir del nombre de la Función y redireciones.
    
    Para terminar, flask pone a nuestra disposición el método url_for() para crear una Url a partir del nombre de la función asociada a la vista. Es recomendable usar url_for() en vez de poner directamente la Url en el código por los siguientes motivos:
  • Si se cambia una url en cualquier momento esta variación no afectará a nuestro código. En el ejemplo anterior podríamos cambiar el decorador @app.route('/hola/') por @app.route('/hello/') y el metodo url_for('bienvenida') nos seguiría dando la url valida.
  • La función escapa los caracteres especiales, como los espacios de forma automática.
  • Las rutas generadas son siempre absolutas evitándose las rutas relativas.
Esta función acepta como parámetros el nombre de una vista y un número variable de argumentos clave-valor cada uno de ellos asociado a una parte variable de la Url. Veamos esto con un ejemplo, donde usaremos otro método muy útil, redirect(), redirigir. Este método nos lleva a la página que le pasemos como parámetro o mejor dicho la url que le proporcionamos con el método url-for. Nótese que empezamos importando los dos nuevos métodos al comienzo del código:


Si en el navegador acedemos a la dirección 127.0.0.1:5000/ir_hola/ el programa anterior nos mandará o redirigirá a la vista ' bienvenida' con el parámetro nombre= Antonio' obteniendo:


Respuestas de Error.

Si queremos en cualquier momento devolver una respuesta HTPP de error, podemos utilizar la función abort. Previamente tendremos que importarla:

from flask import abort

Imaginemos que creamos una vista llamada registro que queremos que de una respuesta de error. Podemos hacer lo siguiente:

@app.route("/registro/")
def registro():
    abort(401)
    

Y si lo ejecutamos, tenemos un error 401:
-------------------------------------------------------------------------------------------------------------------
Unauthorized

The server could not verify that you are authorized to access the URL requested. You either supplied the wrong credentials (e.g. a bad password), or your browser doesn't understand how to supply the credentials required.
--------------------------------------------------------------------------------------------------------------------

En esta página podéis encontrar los códigos de error HTML más comunes, aunque más adelante podrás crear tu propia página de error personalizada.