oscarmlage oscarmlage

Pyramid: 3 - URL Dispatching y ZODB Traversal

Written by oscarmlage on

En capítulos anteriores hemos visto cómo montar el entorno y cómo entenderlo y adaptarlo mínimamente a nuestras necesidades organizativas. Hoy trataremos de abordar el tema del despachador de URL's... ¡qué mal suena en castellano!.

El "URL Dispatching" nos ofrece una manera lo más simple posible de mapear URLs a views. En otras palabras, dada una petición a nuestra aplicación, debemos saber qué parte de la lógica tiene que aplicarse para devolver una respuesta.

Para configurar dicho mapeado, en Pyramid se usa el método pyramid.config.Configurator.add_route(), por ejemplo:

config.add_route('myroute', '/helloworld/',
                 view='myproject.views.helloworld')

Le decimos al framework que si hay una petición del tipo http://aplicacion/helloword/ vaya a ejecutar el método helloworld() dentro de myproject.views.

En la documentación oficial nos recomiendan configurar las rutas de forma centralizada en el __init__.py del proyecto, de forma que por un lado tengamos todas las rutas definidas con add_route y por otro lado, en las vistas, conectemos cada uno de nuestros métodos con una de esas rutas:

config.add_route('myroute', '/prefix/{one}/{two}')
config.add_view(myview, route_name='myroute')

Sin embargo cuando trabajamos con ZODB y Traversal la situación da un giro bastante radical y de poco nos sirve todo lo visto. Si recordamos, a la hora de generar el proyecto le hemos dicho que íbamos a utilizar ZODB, por lo que el __ini__.py generado es ligeramente distinto a la de un proyecto Pyramid normal.

def main(global_config, **settings):
    config = Configurator(root_factory=root_factory, settings=settings)
    config.include('pyramid_chameleon')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.scan()
    return config.make_wsgi_app()

La primera clave que debemos tener clara es que, por defecto, las rutas no se definen con un add_route, sino que van directamente en el decorator @view_config de cada vista. Y el encargado de recopilarlas y buscarlas por toda la aplicación es el config.scan(). De forma que si definimos una view con el name='fulanito', eso se convertirá en una url /fulanito/ dentro de su contexto:

@view_config(name='fulanito', context=myproject.models.MyModel, renderer='templates/fulanito.pt')

Por lo que, poco a poco, según vayamos construyendo la lógica de nuestra aplicación en view, iremos elaborando también el mapeado de rutas de la misma.

La segunda clave para entender el sistema enrutado es el context y Traversal. Y si es lioso de entender, imaginaos de explicar, voy a intentarlo como ejercicio de que "yo también lo he entendido", aunque lo mejor es pasarse por la documentación oficial.

En un sistema gestor de base de datos orientado a objetos como ZODB, cada objeto tiene un path dependiendo de su ubicación, Traversal es el método encargado de manejar y llegar hasta un objeto guardado en la ZODB a partir de su path.

Para poder verlo y entenderlo adecuadamente vamos a compararlo con un almacén robotizado. Todos los distintos tipos de productos están guardados en su estantería y en su ubicación correspondiente dentro del gran almacén (objetos en la ZODB). Cuando en el control del almacén entra un nuevo pedido (request, GET, POST...) hay un brazo robotizado que, dependiendo del pedido, se encarga de ir a la estantería adecuada y recoger el paquete correspondiente para servirlo, pues justo eso es lo que hace Traversal.

¿Y dónde definimos los tipos de objetos que vamos a utilizar en nuestros modelos?, la propia pregunta se responde: en los modelos, bien usando por defecto los disponibles, extendiendo sus funcionalidades o creando nuestros propios tipos de objeto. Guardar objetos en la ZODB de forma persistente es sencillo, existen transacciones, clases propias para ello, etc... nosotros nos basaremos en objetos del tipo Folder para extender su funcionalidad (en algún caso) y trabajar con ellos sin tener que empezar de cero.

Lo bueno de usar una base de datos orientada a objetos es que se adapta perfectamente a los tipos de datos con los que tengas pensado trabajar en tu aplicación. Aunque también tiene cosas menos buenas, como por ejemplo tener que escribir scripts de migración cada vez que cambies o agregues propiedades a tus objetos.

En la siguiente entrada intentaremos escribir nuestro primer modelo de datos funcional.