Tabla de Contenidos

web.py

Uso

Cómo funciona?

web.py se basa en la estructura de las URL de la página web. Para trabajar con este tendremos que…

  1. Importar el módulo web.
  2. Indicar la estructura de la URL.
  3. Indicar qué clases se utilizarán mediante web.application.
import web
urls = (
  '/', 'index'
)
app = web.application(urls, globals())

En el código anterior estamos diciendo que queremos la URL raíz ( / ), que será gestionada por la clase index, las clases que se utilizarán serán las globales del namespace actual.

Indicar las URL

Las URL se indican a partir de una parte que es una expresión regular tal como /, /help/faq, /item/(\d+) (por ejemplo d+ permite una secuencia de dígitos), y otra que es el nombre de la clase que recibirá la petición (index, view…).
Cuando en la expresión regular utilizamos un paréntesis indicamos que ese elemento va a ser utilizado luego, a eso se le llama capturar.
Para la segunda parte podemos indicar, por ejemplo, welcomes.hello (modulo welcomes clase hello), get_\1 donde ese \1 se reemplazará por la primera parte capturada de la expresión regular.

Clases correspondientes a los elementos de la URL

Las clases que indiquemos que se van a utilizar en nuestro site deberan definir los métodos correspondientes a los verbos que queramos implementar (GET, POST…).

class index:
    def GET(self):
        return "Hello, world!"

Ejecución del servidor

Para iniciar el motor de web.py deberemos ejecutar app.run():

if __name__ == "__main__": app.run()

Si ejecutamos el código así, tal cual ($ python code.py), podremos indicar al entorno que escuche por un puerto concreto ($ python code.py 2727) y\o en una dirección concreta ($ python code.py 127.0.0.1 2727, si no lo hiciesemos escucharía por el puerto 8080.

Tratar la entreda

Recoger datos del POST

web.input()				# Devuelve lista de parámetros.

Tratar la salida

Cambiar el content-type

class index:
  def GET(self, code):
    web.header('Content-Type', 'text/xml')
    return render.index(code)

Puedes ver distintos content-type aquí.

Devolver un fichero

def GET(self, code):
  ...
  web.header('Content-Type', 'text/csv')
  web.header('Content-Disposition', 'attachment;filename=myfilename.csv')
  return value

Formularios

Sesiones y autentificación

http://webpy.org/docs/0.3/sessions

Contenido estático

Carpeta static

Podemos agregar una carpeta static en la ruta de la aplicación, esta contendrá los documentos que no cambian. Por ejemplo http://localhost/static/logo.png enviaría la imágen ./static/logo.png.
Una carpeta mapeada a partir de la directiva Alias de Apache también serviría.

A partir de código

import os
import web
 
urls = (
'/images/(.*)', 'images' #this is where the image folder is located....
)
 
class images:
    def GET(self,name):
        ext = name.split(".")[-1] # Gather extension
 
        cType = {
            "png":"images/png",
            "jpg":"image/jpeg",
            "gif":"image/gif",
            "ico":"image/x-icon"            }
 
        if name in os.listdir('images'):  # Security
            web.header("Content-Type", cType[ext]) # Set the Header
            return open('images/%s'%name,"rb").read() # Notice 'rb' for reading images
        else:
            raise web.notfound()

Subir ficheros

Avanzado

Mimerender

Es una librería que parsea el retorno de una URL en el formato indicado.

Código de ejemplo

import web
import json
from mimerender import mimerender
 
render_xml = lambda message: '<message>%s</message>'%message
render_json = lambda **args: json.dumps(args)
render_html = lambda message: '<html><body>%s</body></html>'%message
render_txt = lambda message: message
 
urls = (
    '/(.*)', 'greet'
)
app = web.application(urls, globals())
 
class greet:
    @mimerender(
        default = 'html',
        html = render_html,
        xml  = render_xml,
        json = render_json,
        txt  = render_txt
    )
    def GET(self, name):
        if not name: 
            name = 'world'
        return {'message': 'Hello, ' + name + '!'}
 
if __name__ == "__main__":
    app.run()

Llamadas y retorno

$ curl -H "Accept: application/html" localhost:8080/x
<html><body>Hello, x!</body></html>
$ curl -H "Accept: application/xml" localhost:8080/x
<message>Hello, x!</message>
$ curl -H "Accept: application/json" localhost:8080/x
{'message':'Hello, x!'}
$ curl -H "Accept: text/plain" localhost:8080/x
Hello, x!

Notas

Cómo...

... Usar Cheetah?

... Usar Elixir?

Para utilizar Elixir en un código que utilice web.py simplemente has de lanzar un setup_all() al principio, justo después de haber importado el código del modelo.

... Usarlo en un servidor de producción?

Tipo Apache o Lighttpd.

Notas

Aplicaciones de ejemplo

Ideas para la creación de un proceso en background

:!: Falta probar en producción

#!/usr/bin/python
# -*- coding: utf-8 *-*
 
import web
import json
from mimerender import mimerender
from multiprocessing import Process 
 
render_xml = lambda message: '<message>%s</message>'%message
render_json = lambda **args: json.dumps(args)
render_html = lambda message: '<html><body>%s</body></html>'%message
render_txt = lambda message: message
 
urls = (
    '/(.*)', 'greet'
)
app = web.application(urls, globals())
p = Process()
 
class greet:
    @mimerender(
        default = 'html',
        html = render_html,
        xml  = render_xml,
        json = render_json,
        txt  = render_txt
    )    
    def GET(self, name):
        global p
        p = Process(target = self.test)
        p.start()
        if not name: 
            name = 'world'
        return {'message': 'Hello, ' + name + '!'}
 
    def test (self):
        import os
        print 'entra!!!'
        os.system('ls -laR / > /home/alfred/Desktop/test.txt')
 
if __name__ == "__main__":
    app.run()
    p.join()