URLs amigables en web2py



web2py utiliza una notación para las direcciones de URL en concordancia con el patrón de desarrollo MVC. De este modo, el esquema por defecto para una aplicación web en este framework es el siguiente.

http://.../aplicacion/controlador/funcion

Por ejemplo, en la dirección

http://www.web2py.com/init/default/what

init indica el nombre de una aplicación, default es un controlador y what una función definida dentro del archivo default.py.

Si bien para aplicaciones con enfoque personal o corporativo esto no resulta una inquietud, aquellas orientadas al usuario convencional (una red social, un portal de noticias, un blog) requieren de direcciones más agradables para el consumidor. Además, incorporar URLs amigables optimiza el posicionamiento en buscadores (SEO).

Por ejemplo, sería más conveniente acceder a un formulario de registro vía:

miweb.com/crear-una-cuenta

en oposición a:

miweb.com/myapp/default/user/login

Por otro lado, esta guía también te permitirá soportar URLs antiguas si estás usando web2py para reemplazar una aplicación web obsoleta pero quieres mantener compatibilidad.

Para conseguir esto, estaremos empleando la capacidad de web2py de reescribir direcciones de URLs. Se trata de escribir un conjunto de reglas en el archivo routes.py (ubicado en el directorio de instalación de web2py, y si no existe puedes crearlo) para indicar cómo deben comportarse las URLs. Nótese que esto no quebrará las antiguas direcciones de tu aplicación, y no tendrás que reemplazar ninguna dirección en tus vistas o controladores, siempre y cuando hayas usado la función URL.

web2py provee dos métodos para configurar direcciones de URL. Un sistema básico basado en parámetros y otro (no tanto) más complejo fundado en patrones. Ambos métodos no pueden mezclarse, y para emplear URLs amigables es necesario utilizar aquél basado en patrones. Si ya cuentas con una aplicación que hace uso del sistema basado en parámetros, no hay de qué preocuparse, migrar de un método a otro no es una tarea ardua.

Empezamos por abrir el archivo routes.py o bien crearlo si no existe. Si dentro del archivo encuentras lo siguiente:

routers = dict(
    # base router
    BASE=dict(
        default_application='welcome',
    ),
)

Eso indica que estás usando el sistema basado en parámetros. Allí está definido que la aplicación por defecto es “welcome”, de modo que http://.../ equivale a http://.../welcome/default/index. Para cambiar la aplicación por defecto en el sistema basado en patrones, vamos a reemplazar el código anterior (completo) por simplemente:

default_application = "myapp"

Para observar los cambios es necesario recargar las rutas, reiniciando web2py.

Si tu archivo de rutas definía routes_onerror puedes conservarlo intacto ya que es soportado por ambos sistemas.

Ahora bien, el sistema basado en patrones consiste en definir URLs de entrada (routes_in) y de salida (routes_out). Ambas listas contendrán tuplas indicando, en primer lugar, un patrón y, en segundo lugar, la dirección de URL con la que está asociado.

Por ejemplo, si contamos con un formulario de registro en /myapp/default/register, podemos enlazarlo con /crear-una-cuenta de la siguiente forma:

routes_in = [
    ("/crear-una-cuenta", "/myapp/default/register")
]

En este caso, el formulario puede ser accedido a través de ambas direcciones. Además, queremos que la función URL retorne /crear-una-cuenta al llamar a URL("default", "register"). Para esto hacemos uso de routes_out a continuación del código anterior.

routes_out = [
    ("/myapp/default/register", "/crear-una-cuenta")
]

Como puedes observar, routes_out es una lista con elementos inversos respecto de routes_in. Por ende, para la mayoría de los casos será suficiente utilizar el siguiente código.

routes_out = [(y, x) for x, y in routes_in]

Este código creará automáticamente las direcciones de salida respecto de las de entrada. Nótese que este método no funciona si el patrón incluye expresiones regulares, como veremos a continuación.

Hasta el momento resultó bastante sencillo asignar una URL amigable a un controlador determinado. Sin embargo, los patrones que empleamos fueron bastante sencillos. El sistema basado en patrones de web2py permite especificar expresiones regulares para patrones más complejos. Sin embargo, para la mayoría de los casos será suficiente evitar las expresiones regulares y, en su lugar, emplear alguno de los 4 placeholders que provee el framework.

Por defecto, web2py incorpora el siguiente patrón, como vimos al comienzo del artículo.

routes_in = [
    ("/$a/$c/$f", "/$a/$c/$f")
]

En donde $a, $c y $f representan el nombre de una aplicación, un controlador y una función. Estos placeholders pueden utilizarse, por ejemplo, para omitir la aplicación y controlador por defecto.

routes_in = [
    ("/$f", "/myapp/default/$f"),
]

De esta forma, siempre que se omitan el nombre de la aplicación y el controlador, indicando únicamente el nombre de uan función, se tomará por defecto la aplicación “myapp” y el controlador “default”. En nuestro caso, la dirección /register es vinculada con /myapp/default/register.

El cuarto placeholder es $anything que nomina, como su nombre lo indica, cualquier cosa (similar a (.*) en una expresión regular). En el código anterior, /register?a=1 satisface el patrón especificado (/$f), pero /register/1 no lo hace. Para esto, podemos utilizar:

routes_in = [
    ("/$f", "/myapp/default/$f"),
    ("/$f/$anything", "/myapp/default/$f/$anything"),
]

También resulta útil para remover el nombre de la aplicación de la dirección de URL.

routes_in = [
    # Controlador por defecto.
    ("/$f", "/myapp/default/$f"),
    ("/$f/$anything", "/myapp/default/$f/$anything"),
    # Aplicación por defecto.
    ("/$anything", "/myapp/$anything"),
]

Con esta introducción, toda dirección de URL será asignada a la aplicación “myapp”.

Nótese que el orden de los patrones es importante. web2py los ejecutará según su definición. La dirección /register satisface tanto el primer como el último patrón, pero el primero es considerado por ser justamente la primera coincidencia.

Por último, añadimos dos patrones para exponer tanto la aplicación admin como el controlador appadmin en sus direcciones correspondientes.

routes_in = [
    # Exponer admin y appadmin.
    ("/admin$anything", "/admin$anything"),
    ("/appadmin$anything", "/myapp/appadmin$anything"),
    # Controlador por defecto.
    ("/$f", "/myapp/default/$f"),
    ("/$f/$anything", "/myapp/default/$f/$anything"),
    # Aplicación por defecto.
    ("/$anything", "/myapp/$anything"),
]

Por lo comentado anteriormente, ambos patrones deben ubicarse al comienzo.

Código completo:

# -*- coding: utf-8 -*-

default_application = "myapp"

routes_in = [
    # Exponer admin y appadmin.
    ("/admin$anything", "/admin$anything"),
    ("/appadmin$anything", "/myapp/appadmin$anything"),
    # Controlador por defecto.
    ("/$f", "/myapp/default/$f"),
    ("/$f/$anything", "/myapp/default/$f/$anything"),
    # Aplicación por defecto.
    ("/$anything", "/myapp/$anything"),
]

routes_out = [(y, x) for x, y in routes_in]



Deja un comentario