Ejemplos de web2pyTM

Examples: simple | sesión | plantilla | layout | formulario | base de datos | cache | pruebas | streaming | xmlrpc

Ejemplos simples

Aquí hay algunos ejemplos completos y funcionales que explican la sintaxis básica del framework.
Puede presionar en las palabras claves de web2py (¡en el código resaltado!) para tener información.

Ejemplo 1

En el contrlador: simple_examples.py
1.
2.
def hello1():
return "Hello World"

Si la función de controlador devuelve una cadena, esta es el cuerpo de la página generada.
Pruebelo aquí: hello1

Ejemplo 2

En el controlador: simple_examples.py
1.
2.
def hello2():
return T("Hello World") # hola mundo!

La función T() marca las cadenas que necesitan ser traducidas. Los diccionarios de traducción pueden ser creados en /admin/default/design
Pruebelo aquí: hello2

Ejemplo 3

En el controlador: simple_examples.py
1.
2.
def hello3():
return dict(message=T("Hello World"))
y la vista: simple_examples/hello3.html
1.
2.
3.
{{extend 'layout.html'}}
<h1>{{=message}}</h1>

Si devuelve un diccionario, las variables definidas como claves del diccionario son visibles a la vista (plantilla).
Pruebelo aquí: hello3

Las acciones pueden ser generadas en otros formatos como JSON, hello3.json, and XML, hello3.xml

Ejemplo 4

En el controlador: simple_examples.py
1.
2.
3.
def hello4():
response.view='simple_examples/hello3.html'
return dict(message=T("Hello World"))

Puede cambiar la vista, pero lo predeterminado es /[controller]/[function].html. Si la predeterminada no se encuentra web2py trata de generar la página usando la vista generic.html.
Pruebelo aquí: hello4

Ejemplo 5

En el controlador: simple_examples.py
1.
2.
def hello5():
return HTML(BODY(H1(T('Hello World'),_style="color: red;"))).xml() # .xml to serialize

Puede también generar HTML usando objetos ayudantes HTML, BODY, H1, etc. Cada uno de estas etiquetas es una clase y la vista conoce como representarla. El método .xml() las serializa y produce el código html/xml para la página. Cada etiqueta, DIV por ejemplo, toma tres tipos de argumentos:

Pruebelo aquí: hello5

Ejemplo 6

En el controlador: simple_examples.py
1.
2.
3.
def hello6():
response.flash=T("Hello World in a flash!")
return dict(message=T("Hello World"))

response.flash permite que ud. muestre un mensaje parpadeante al usuario cuando la página es devuelta. Use session.flash en vez de response.flash para mostrar un mensaje luego de una redirección. Con el layout por defecto, puede presionar sobre el mensaje parpadeante para que desaparezca.
Pruebelo aquí: hello6

Ejemplo 7

En el controlador: simple_examples.py
1.
2.
def status():
return dict(request=request,session=session,response=response)

Aqui estamos mostrando los objetos del requerimiento, sesión y respuesta usando la plantilla predeterminada generic.html.
Pruebelo aquí: status

Ejemplo 8

En el controlador: simple_examples.py
1.
2.
def redirectme():
redirect(URL(r=request,f='hello3'))

Puede hacer redirecciones.
Pruebelo aquí: redirectme

Ejemplo 9

En el controlador: simple_examples.py
1.
2.
def raisehttp():
raise HTTP(400,"internal error")

Puede lanzar excepciones HTTP para devolver mensaje de error.
Pruebelo aquí: raisehttp

Ejemplo 10

En el controlador: simple_examples.py
1.
2.
3.
def raiseexception():
1/0
return 'oops'

Si una excepción ocurre (otra que HTTP) un ticket es generado y el evento es registrado para el administrador. Estos tickets y bitácoras pueden ser accedidos, revisados y eliminados en cualquier momento.
Pruebelo aquí: raiseexception

Ejemplo 11

En el controlador: simple_examples.py
1.
2.
3.
4.
def servejs():
import gluon.contenttype
response.headers['Content-Type']=gluon.contenttype.contenttype('.js')
return 'alert("This is a Javascript document, it is not supposed to run!");'

Puede servir algo distinto a páginas HTML al cambiar el contenttype (tipo de contenido) vía los response.headers (encabezados de respuesta). El módulo gluon.contenttype puede ayudarlo a darse cuenta el tipo del archivo a servir. NOTA: esto no es necesario para los archivos estáticos salvo que desee requerir autorización.
Pruebelo aquí: servejs

Ejemplo 12

En el controlador: simple_examples.py
1.
2.
def makejson():
return response.json(['foo', {'bar': ('baz', None, 1.0, 2)}])

Si usa Ajax, web2py incluye gluon.contrib.simplejson, desarrollado por Bob Ippolito. Este módulo provee una manera rápida y fácil de servir contenidos asincrónicos a su página Ajax. gluon.simplesjson.dumps(...) puede serializar la mayoría de los tipos de Python a JSON. gluon.contrib.simplejson.loads(...) realiza la operación inversa.
Pruebelo aquí: makejson

Nuevo en web2py 1.63: Cualquier acción normal devolviendo un dict es automáticamente serializada a JSON si se agrega '.json' a la URL.

Ejemplo 13

En el controlador: simple_examples.py
1.
2.
3.
4.
5.
6.
7.
8.
9.
def makertf():
import gluon.contrib.pyrtf as q
doc=q.Document()
section=q.Section()
doc.Sections.append(section)
section.append('Section Title')
section.append('web2py is great. '*100)
response.headers['Content-Type']='text/rtf'
return q.dumps(doc)

web2py también incluye gluon.contrib.pyrtf, desarrollado por Simon Cusack y revisado por Grant Edwards. Este módulo permite generar documentos Rich Text Format (Texto de Formato Enriquecido) incluyendo texto coloreado y formateado junto con imágenes.
Pruebelo aquí: makertf

Ejemplo 14

En el controlador: simple_examples.py
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
def rss_aggregator():
import datetime
import gluon.contrib.rss2 as rss2
import gluon.contrib.feedparser as feedparser
d = feedparser.parse("http://rss.slashdot.org/Slashdot/slashdot/to")

rss = rss2.RSS2(title=d.channel.title,
link = d.channel.link,
description = d.channel.description,
lastBuildDate = datetime.datetime.now(),
items = [
rss2.RSSItem(
title = entry.title,
link = entry.link,
description = entry.description,
# guid = rss2.Guid('unkown'),
pubDate = datetime.datetime.now()) for entry in d.entries]
)
response.headers['Content-Type']='application/rss+xml'
return rss2.dumps(rss)

web2py incluyegluon.contrib.rss2, desarrollado por Dalke Scientific Software, el cual genera RSS2 feeds, y gluon.contrib.feedparser, desarrollado por Mark Pilgrim, el cual recolecta RSS y ATOM feeds. El controlador de arriba recolecta feeds de slashdot y hace uno nuevo.
Pruebelo aquí: rss_aggregator

Ejemplo 15

En el controlador: simple_examples.py
1.
2.
3.
4.
5.
6.
7.
8.
9.
from gluon.contrib.markdown import WIKI

def ajaxwiki():
form=FORM(TEXTAREA(_id='text'),INPUT(_type='button',_value='markdown',
_onclick="ajax('ajaxwiki_onclick',['text'],'html')"))
return dict(form=form,html=DIV(_id='html'))

def ajaxwiki_onclick():
return WIKI(request.vars.text).xml()

web2py también incluye gluon.contrib.markdown (markdown2) el que convierte WIKI markup a HTML siguiendo esta sintáxis. In this example we added a fancy ajax effect.
Pruebelo aquí: ajaxwiki

Ejemplos de Sesión

Ejemplo 16

En el controlador: session_examples.py
1.
2.
3.
4.
def counter():
if not session.counter: session.counter=0
session.counter+=1
return dict(counter=session.counter)
y en la vista: session_examples/counter.html
1.
2.
3.
4.
5.
6.
{{extend 'layout.html'}}
<h1>session counter</h1>

<h2>{{for i in range(counter):}}{{=i}}...{{pass}}</h2>

<a href="{{=URL(r=request)}}">click me to count</a>

Presione para contar. El session.counter es persistente para este usario y aplicación. Cada aplicación dentro del sistema tiene su propio y separado gestor de sesión.
Pruebelo aquí: counter

Ejemplos de plantillas

Ejemplo 17

En el controlador: template_examples.py
1.
def variables(): return dict(a=10, b=20)
y en la vista: template_examples/variables.html
1.
2.
3.
4.
{{extend 'layout.html'}}
<h1>Your variables</h1>
<h2>a={{=a}}</h2>
<h2>a={{=b}}</h2>

Una vista (también conocida como template o plantilla) es simplemente un archivo HTML con etiquetas {{...}}. Puede poner CUALQUIER código python dentro de las etiquetas, no necesita sangrar (indentar) pero debe usar pass para cerrar los bloques. La vista es transformada a código python y es ejecutada. {{=a}} imprime a.xml() o escape(str(a)).
Pruebelo aquí: variables

Ejemplo 18

En el controlador: template_examples.py
1.
def test_for(): return dict()
y en la vista: template_examples/test_for.html
1.
2.
3.
4.
5.
6.
{{extend 'layout.html'}}
<h1>For loop</h1>

{{for number in ['one','two','three']:}}
<h2>{{=number.capitalize()}}<h2>
{{pass}}

Puede hacer bucles while y ciclos for.
Pruebelo aquí: test_for

Ejemplo 19

En el controlador: template_examples.py
1.
def test_if(): return dict()
y en la vista: template_examples/test_if.html
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
{{extend 'layout.html'}}
<h1>If statement</h1>

{{
a=10
}}


{{if a%2==0:}}
<h2>{{=a}} is even</h2>
{{else:}}
<h2>{{=a}} is odd</h2>
{{pass}}

Puede hacer condiciones if, elif, else.
Pruebelo aquí: test_if

Ejemplo 20

En el controlador: template_examples.py
1.
def test_try(): return dict()
y en la vista: template_examples/test_try.html
1.
2.
3.
4.
5.
6.
7.
8.
{{extend 'layout.html'}}
<h1>Try... except</h1>

{{try:}}
<h2>a={{=1/0}}</h2>
{{except:}}
infinity</h2>
{{pass}}

Puede hacer try, except, finally (manejo de excepciones).
Pruebelo aquí: test_try

Ejemplo 21

En el controlador: template_examples.py
1.
def test_def(): return dict()
y en la vista: template_examples/test_def.html
1.
2.
3.
4.
5.
6.
7.
{{extend 'layout.html'}}
{{def itemlink(name):}}<li>{{=A(name,_href=name)}}</li>{{return}}
<ul>
{{itemlink('http://www.google.com')}}
{{itemlink('http://www.yahoo.com')}}
{{itemlink('http://www.nyt.com')}}
</ul>

También puede escribir funciones en HTML.
Pruebelo aquí: test_def

Ejemplo 22

En el controlador: template_examples.py
1.
def escape(): return dict(message='<h1>text is escaped</h1>')
y en la vista: template_examples/escape.html
1.
2.
3.
4.
5.
{{extend 'layout.html'}}
<h1>Strings are automatically escaped</h1>

<h2>Message is</h2>
{{=message}}

El argumento de {{=...}} siempre es escapado salvo que sea un objeto con método .xml() como un enlace, A(...), un FORM(...), un bloque XML(...), etc.
Pruebelo aquí: escape

Ejemplo 23

En el controlador: template_examples.py
1.
2.
def xml():
return dict(message=XML('<h1>text is not escaped</h1>'))
y en la vista: template_examples/xml.html
1.
2.
3.
4.
5.
{{extend 'layout.html'}}
<h1>XML</h1>

<h2>Message is</h2>
{{=message}}

Si no desea escapar el argumento de {{=...}} marquelo como XML.
Pruebelo aquí: xml

Ejemplo 24

En el controlador: template_examples.py
1.
def beautify(): return dict(message=BEAUTIFY(request))
y en la vista: template_examples/beautify.html
1.
2.
3.
4.
5.
{{extend 'layout.html'}}
<h1>BEAUTIFY</h1>

<h2>Message is</h2>
{{=message}}

Puede usar BEAUTIFY para tornar listas y diccionarios a HTML organizado.
Pruebelo aquí: beautify

Layout Examples

Ejemplo 25

En el controlador: layout_examples.py
1.
2.
3.
4.
5.
6.
def civilized():
response.menu=[['civilized',True,URL(r=request,f='civilized')],
[
'slick',False,URL(r=request,f='slick')],
[
'basic',False,URL(r=request,f='basic')]]
response.flash='you clicked on civilized'
return dict(message="you clicked on civilized")
y en la vista: layout_examples/civilized.html
1.
2.
3.
{{extend 'layout_examples/layout_civilized.html'}}
<h2>{{=message}}</h2>
<p>{{for i in range(1000):}}bla {{pass}} </p>

Puede especificar el archivo de layout al comienzo de su vista. Un archivo Layout civilizado es una vista que contiene {{include}} en algún lugar.
Pruebelo aquí: civilized

Ejemplo 26

En el controlador: layout_examples.py
1.
2.
3.
4.
5.
6.
def slick():
response.menu=[['civilized',False,URL(r=request,f='civilized')],
[
'slick',True,URL(r=request,f='slick')],
[
'basic',False,URL(r=request,f='basic')]]
response.flash='you clicked on slick'
return dict(message="you clicked on slick")
y en la vista: layout_examples/slick.html
1.
2.
3.
{{extend 'layout_examples/layout_sleek.html'}}  
<h2>{{=message}}</h2>
{{for i in range(1000):}}bla {{pass}}

Lo mismo aquí, pero usando una plantilla diferente.
Pruebelo aquí: slick

Ejemplo 27

En el controlador: layout_examples.py
1.
2.
3.
4.
5.
6.
def basic():
response.menu=[['civilized',False,URL(r=request,f='civilized')],
[
'slick',False,URL(r=request,f='slick')],
[
'basic',True,URL(r=request,f='basic')]]
response.flash='you clicked on basic'
return dict(message="you clicked on basic")
y en la vista: layout_examples/basic.html
1.
2.
3.
{{extend 'layout.html'}}  
<h2>{{=message}}</h2>
{{for i in range(1000):}}bla {{pass}}

'layout.html' es la plantilla predeterminada, cada aplicación tiene una copia de ella.
Pruebelo aquí: basic

Ejemplos de formularios

Ejemplo 28

En el controlador: form_examples.py
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
def form():
form=FORM(TABLE(TR("Su nombre:",INPUT(_type="text",_name="name",requires=IS_NOT_EMPTY())),
TR("Su correo:",INPUT(_type="text",_name="email",requires=IS_EMAIL())),
TR("¿Admin?",INPUT(_type="checkbox",_name="admin")),
TR("¿Seguro?",SELECT('yes','no',_name="sure",requires=IS_IN_SET(['yes','no']))),
TR("Perfil",TEXTAREA(_name="profile",value="write something here")),
TR("",INPUT(_type="submit",_value="SUBMIT"))))
if form.accepts(request.vars,session):
response.flash="formulario aceptado"
elif form.errors:
response.flash="formulario inválido"
else:
response.flash="por favor complete el formulario"
return dict(form=form,vars=form.vars)

Puede usar ayudantes HTML como FORM, INPUT, TEXTAREA, OPTION, SELECT para construir un formulario. El atributo "value=" establece el valor inicial de un campo (también funciona para TEXTAREA y OPTION/SELECT) y el atributo "requires" establece los validadores. FORM.accepts(..) intenta validar el formulario y, si hay éxito, almacena las variables vars en form.vars. Si hay fallo el mensaje de error se almacena en form.errors y se muestra en el formulario.
Pruebelo aquí: form

Ejemplo con Bases de Datos

Puede encontrar más ejemplos de la Capa de Abstracción de la Base de Datos aquí

Vamos a crear un modelo simple con clientes (users), perros (dogs), productos (products) y compras (purchases) -la base de datos de una tienda de mascotas-. Los clientes pueden tener muchos perros (UNO A MUCHOS), pueden comprar muchos productos y cada producto puede tener muchos compradores (MUCHOS A MUCHOS).

Ejemplo 29

en el modelo: db.py
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
db=DAL('sqlite://storage.db')

# clientes (nombre, email)
db.define_table('users',
Field('name'),
Field('email'))

# UN (cliente) A MUCHOS (perros)
# perros (id_propietario, nombre, tipo, vacunado, fotografía)
db.define_table('dogs',
Field('owner_id',db.users),
Field('name'),
Field('type'),
Field('vaccinated','boolean',default=False),
Field('picture','upload',default=''))

# productos (nombre, descripción)
db.define_table('products',
Field('name'),
Field('description','text'))

# MUCHOS (clientes) A MUCHOS (productos)
# compras (id_comprador, id_producto, cantidad)
db.define_table('purchases',
Field('buyer_id',db.users),
Field('product_id',db.products),
Field('quantity','integer'))

purchased=((db.users.id==db.purchases.buyer_id)&(db.products.id==db.purchases.product_id))

# Validadores:
db.users.name.requires=IS_NOT_EMPTY() # nombre de cliente no vacio
db.users.email.requires=[IS_EMAIL(), IS_NOT_IN_DB(db,'users.email')] # email válido y no existente
db.dogs.owner_id.requires=IS_IN_DB(db,'users.id','users.name') # propietario sea cliente existente
db.dogs.name.requires=IS_NOT_EMPTY() # nombre del perro no vacio
db.dogs.type.requires=IS_IN_SET(['pequeño','mediano','grande']) # tipo de perro
db.purchases.buyer_id.requires=IS_IN_DB(db,'users.id','users.name') # comprador sea cliente existente
db.purchases.product_id.requires=IS_IN_DB(db,'products.id','products.name') # producto existente
db.purchases.quantity.requires=IS_INT_IN_RANGE(0,10) # cantidad en el rango 0 a 10

Las tablas son creadas si no existen (try... except). Aqui "purchased" es un objeto SQLQuery (consulta sql), "db(purchased)" serán los objetos SQLSet (conjunto de resultados sql). Un SQLSet puede ser seleccionado (select), actualizado (update) y eliminado (delete). SQLSets también puede ser intersectado. Los tipos de campos permitidos son string, integer, password, text, blob, upload, date, time, datetime, references(*), e id(*). El campo id está por defecto y no debe ser declarado. references es para uno a muchos o muchos a muchos como en el ejemplo superior. Para campos strings debería especificar la longitud u obtendrá length=32.

Puede usar db.tablename.fieldname.requires= para establecer las restricciones a los valores de los campos. Estas restricciones son automáticamente convertidas a widgets (artefactos) al generar los formularios desde las tablas con SQLFORM(db.tablename).

define_tables crea la tabla e intenta una migración si la tabla ha sido modificada o si el nombre de la base de datos ha cambiado desde la última vez. Si ya sabe que ya tiene la tabla en la base de datos y no desea intentar una migración, use como último argumento de define_table migrate=False.

Ejemplo 30

En el controlador: database_examples.py
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
response.menu=[['Registrar Usuario',False,URL(r=request,f='register_user')],
[
'Registrar Perro',False,URL(r=request,f='register_dog')],
[
'Registrar Producto',False,URL(r=request,f='register_product')],
[
'Comprar Producto',False,URL(r=request,f='buy')]]

def register_user():
### crea e inserta un formulario form para la tabla users
form=SQLFORM(db.users)
### si el formulario es correcto, realizar el insert
if form.accepts(request.vars,session):
response.flash='nuevo registro insertado'
### y obtener una lista de todos los usuarios
records=SQLTABLE(db().select(db.users.ALL))
return dict(form=form,records=records)
y en la vista: database_examples/register_user.html
1.
2.
3.
4.
5.
6.
{{extend 'layout_examples/layout_civilized.html'}}

<h1>User registration form</h1>
{{=form}}
<h2>Current users</h2>
{{=records}}

Este es un formulario simple de registración de usuario. SQLFORM toma una tabla y devuelve el formulario de entrada correspondiente con validadores, etc. SQLFORM.accepts es similar a FORM.accepts pero, si el formulario es validado, el insert correspondiente también es realizado. SQLFORM puede también hacer modificaciones y editar si un registro es pasado como su segundo argumento. SQLTABLE en cambio convierte unconjunto de registros (resultado de un select) en una tabla HTML con enlaces especificados por sus parámetros opcionales. El response.menu arriba es simplemente una variable usada por el layout para hacer el menú de navegación para todas las funciones en este controlador.
Pruebelo aquí: register_user

Ejemplo 31

En el controlador: database_examples.py
1.
2.
3.
4.
5.
6.
7.
def register_dog():
form=SQLFORM(db.dogs)
if form.accepts(request.vars,session):
response.flash='new record inserted'
download=URL(r=request,f='download') # to see the picture
records=SQLTABLE(db().select(db.dogs.ALL),upload=download)
return dict(form=form,records=records)
y en la vista: database_examples/register_dog.html
1.
2.
3.
4.
5.
6.
{{extend 'layout_examples/layout_civilized.html'}}

<h1>Dog registration form</h1>
{{=form}}
<h2>Current dogs</h2>
{{=records}}

Here is a dog registration form. Notice that the "image" (type "upload") field is rendered into a <INPUT type="file"> html tag. SQLFORM.accepts(...) handles the upload of the file into the uploads/ folder.
Pruebelo aquí: register_dog

Ejemplo 32

En el controlador: database_examples.py
1.
2.
3.
4.
5.
6.
def register_product():
form=SQLFORM(db.products)
if form.accepts(request.vars,session):
response.flash='new record inserted'
records=SQLTABLE(db().select(db.products.ALL))
return dict(form=form,records=records)
y en la vista: database_examples/register_product.html
1.
2.
3.
4.
5.
6.
{{extend 'layout_examples/layout_civilized.html'}}

<h1>Product registration form</h1>
{{=form}}
<h2>Current products</h2>
{{=records}}

Nada nuevo aquí.
Pruebelo aquí: register_product

Ejemplo 33

En el controlador: database_examples.py
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
def buy():
form=FORM(TABLE(TR("Buyer id:",INPUT(_type="text",_name="buyer_id",requires=IS_NOT_EMPTY())),
TR("Product id:",INPUT(_type="text",_name="product_id",requires=IS_NOT_EMPTY())),
TR("Quantity:",INPUT(_type="text",_name="quantity",requires=IS_INT_IN_RANGE(1,100))),
TR("",INPUT(_type="submit",_value="Order"))))
if form.accepts(request.vars,session):
### verifica si el usuario está en la base de datos
if len(db(db.users.id==form.vars.buyer_id).select())==0:
form.errors.buyer_id="comprador no está en la base de datos"
### verifica si el producto está en la base de datos
if len(db(db.products.id==form.vars.product_id).select())==0:
form.errors.product_id="producto no está en la base de datos"
### si no hay error
if len(form.errors)==0:
### obtener una lista de las compras similares del usuario
purchases=db((db.purchases.buyer_id==form.vars.buyer_id)&
(
db.purchases.product_id==form.vars.product_id)).select()
### si la lista contiene un registro, actualizarlo
if len(purchases)>0:
purchases[0].update_record(quantity=purchases[0].quantity+form.vars.quantity)
### o insertar un nuevo registro en la tabla
else:
db.purchases.insert(buyer_id=form.vars.buyer_id,
product_id=form.vars.product_id,
quantity=form.vars.quantity)
response.flash="producto comprado!"
if len(form.errors): response.flash="valores inválidos en el formulario!"
### ahora obtener una lista de todas las compras
records=db(purchased).select(db.users.name,db.purchases.quantity,db.products.name)
return dict(form=form,records=SQLTABLE(records),vars=form.vars,vars2=request.vars)
y en la vista: database_examples/buy.html
1.
2.
3.
4.
5.
6.
7.
{{extend 'layout_examples/layout_civilized.html'}}
<h1>Purchase form</h1>
{{=form}}
[ {{=A('reset purchased',_href=URL(r=request,f='reset_purchased'))}} |
{{=A('delete purchased',_href=URL(r=request,f='delete_purchased'))}} ]<br/>
<h2>Current purchases (SQL JOIN!)</h2>
<p>{{=records}}</p>

Aquí hay un ejemplo de formulario de compra más sofisticado. Verifica que el comprador y el producto esten en la base de datos y acualiza el registro correspondiente o inserta una nueva compra. También hace un JOIN para listar todas las compras.
Pruebelo aquí: buy

Ejemplo 34

En el controlador: database_examples.py
1.
2.
3.
def delete_purchased():
db(db.purchases.id>0).delete()
redirect(URL(r=request,f='buy'))
Pruebelo aquí: delete_purchased

Ejemplo 35

En el controlador: database_examples.py
1.
2.
3.
def reset_purchased():
db(db.purchases.id>0).update(quantity=0)
redirect(URL(r=request,f='buy'))

Esto es una actualización sobre un SQLSet. (db.purchase.id>0 identifica un conjunto conteniendo solo las db.purchases.)
Pruebelo aquí: reset_purchased

Ejemplo 36

En el controlador: database_examples.py
1.
2.
def download():
return response.download(request,db)

Este controlador permite a los usuarios descargar las fotos subidas de los perros. Recordar la sentencia upload=URL(...'download'...) en la función de registro de perros. Notar que en la ruta URL /application/controller/function/a/b/etc a, b, etc son pasadas al controlador como request.args[0], request.args[1], etc. Dado que la URL es validada request.args[] siempre contiene nombres de archivos válidos y no '~' o '..' etc. Esto es útil para permitir a los visitantes enlazar los archivos.

Ejemplos de Cache

Ejemplo 37

En el controlador: cache_examples.py
1.
2.
3.
4.
def cache_in_ram():
import time
t=cache.ram('time',lambda:time.ctime(),time_expire=5)
return dict(time=t,link=A('click to reload',_href=URL(r=request)))

La salida de lambda:time.ctime() es mantenida en la cache de ram por 5 segundos. La cadena 'time' es usada como clave de cache.
Pruebelo aquí: cache_in_ram

Ejemplo 38

En el controlador: cache_examples.py
1.
2.
3.
4.
def cache_on_disk():
import time
t=cache.disk('time',lambda:time.ctime(),time_expire=5)
return dict(time=t,link=A('click to reload',_href=URL(r=request)))

La salida de lambda:time.ctime() es almacenada en la cached de disco (usando el módulo shelve) por 5 segundos.
Pruebelo aquí: cache_on_disk

Ejemplo 39

En el controlador: cache_examples.py
1.
2.
3.
4.
5.
def cache_in_ram_and_disk():
import time
t=cache.ram('time',lambda:cache.disk('time',
lambda:time.ctime(),time_expire=5),time_expire=5)
return dict(time=t,link=A('click to reload',_href=URL(r=request)))

La salida de lambda:time.ctime() es almacenada en la cached de disco (usando el módulo shelve) por 5 segundos. web2py mira en ram primero y si no está ahí mira en el disco. Si no está en el disco llama a la función. EWsto es útil en ambientes multiproceso. Los dos tiempos no tienen por que ser los mismos.
Pruebelo aquí: cache_in_ram_and_disk

Ejemplo 40

En el controlador: cache_examples.py
1.
2.
3.
4.
5.
@cache(request.env.path_info,time_expire=5,cache_model=cache.ram)
def cache_controller_in_ram():
import time
t=time.ctime()
return dict(time=t,link=A('click to reload',_href=URL(r=request)))

Here the entire controller (dictionary) is cached in ram for 5 seconds. The result of a select cannot be cached unless it is first serialized into a table lambda:SQLTABLE(db().select(db.users.ALL)).xml(). You can read below for an even better way to do it.
Pruebelo aquí: cache_controller_in_ram

Ejemplo 41

En el controlador: cache_examples.py
1.
2.
3.
4.
5.
@cache(request.env.path_info,time_expire=5,cache_model=cache.disk)
def cache_controller_on_disk():
import time
t=time.ctime()
return dict(time=t,link=A('click to reload',_href=URL(r=request)))

Here the entire controller (dictionary) is cached on disk for 5 seconds. This will not work if the dictionary contains unpickleable objects.
Pruebelo aquí: cache_controller_on_disk

Ejemplo 42

En el controlador: cache_examples.py
1.
2.
3.
4.
5.
6.
@cache(request.env.path_info,time_expire=5,cache_model=cache.ram)
def cache_controller_and_view():
import time
t=time.ctime()
d=dict(time=t,link=A('click to reload',_href=URL(r=request)))
return response.render(d)

response.render(d) renders the dictionary inside the controller, so everything is cached now for 5 seconds. This is best and fastest way of caching!
Pruebelo aquí: cache_controller_and_view

Ejemplo 43

En el controlador: cache_examples.py
1.
2.
3.
4.
5.
6.
def cache_db_select():
import time
db.users.insert(name='somebody',email='gluon@mdp.cti.depaul.edu')
records=db().select(db.users.ALL,cache=(cache.ram,5))
if len(records)>20: db(db.users.id>0).delete()
return dict(records=records)

The results of a select are complex unpickleable objects that cannot be cached using the previous method, but the select command takes an argument cache=(cache_model,time_expire) and will cache the result of the query accordingly. Notice that the key is not necessary since key is generated based on the database name and the select string.
Pruebelo aquí: cache_db_select

Ajax Examples

Ejemplo 44

En el controlador: ajax_examples.py
1.
2.
3.
4.
5.
6.
7.
8.
def index():
return dict()

def data():
if not session.m or len(session.m)==10: session.m=[]
if request.vars.q: session.m.append(request.vars.q)
session.m.sort()
return TABLE(*[TR(v) for v in session.m]).xml()
In view: ajax_examples/index.html
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
{{extend 'layout.html'}}

<p>Type something and press the button.
The last 10 entries will appear sorted in a table below.</p>

<form>
<INPUT type="text" id='q' value="web2py"/>
<INPUT type="button" value="submit"
onclick="ajax('{{=URL(r=request,f='data')}}',['q'],'target');"/>
</form>
<br/>
<div id="target"></div>

The javascript function "ajax" is provided in "web2py_ajax.html" and included by "layout.html". It takes three arguments, a url, a list of ids and a target id. When called, it sends to the url (via a get) the values of the ids and display the response in the value (of innerHTML) of the target id.
Pruebelo aquí: index

Ejemplo 45

En el controlador: ajax_examples.py
1.
2.
3.
def flash():
response.flash='this text should appear!'
return dict()

Pruebelo aquí: flash

Ejemplo 46

En el controlador: ajax_examples.py
1.
2.
def fade():
return dict()
In view: ajax_examples/fade.html
1.
2.
3.
4.
5.
6.
7.
8.
{{extend 'layout.html'}}

<form>
<input type="button" onclick="fade('test',-0.2);" value="fade down"/>
<input type="button" onclick="fade('test',+0.2);" value="fade up"/>
</form>

<div id="test">{{='Hello World '*100}}</div>

Pruebelo aquí: fade

Excel-like spreadsheet via Ajax

Web2py includes a widget that acts like an Excel-like spreadsheet and can be used to build forms [read more].

Testing Examples

Ejemplo 47

Using the Python doctest notation it is possible to write tests for all controller functions. Tests are then run via the administrative interface which generates a report. Here is an example of a test in the code:

1.
2.
3.
4.
5.
6.
7.
8.
def index():
'''
This is a docstring. The following 3 lines are a doctest:
>>> request.vars.name='Max'
>>> index()
{'name': 'Max'}
'''
return dict(name=request.vars.name)

Streaming Examples

Ejemplo 48

It is very easy in web2py to stream large files. Here is an example of a controller that does so:

1.
2.
3.
4.
def streamer():
import os
path=os.path.join(request.folder,'private','largefile.mpeg4')
return response.stream(open(path,'rb'),chunk_size=4096)

By default all static files and files stored in 'upload' fields in the database are streamed when larger than 1MByte.

web2py automatically and transparently handles PARTIAL_CONTENT and RANGE requests.

XML-RPC Examples

Ejemplo 49

Web2py has native support for the XMLRPC protocol. Below is a controller function "handler" that exposes two functions, "add" and "sub" via XMLRPC. The controller "tester" executes the two function remotely via xmlrpc.

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
from gluon.tools import Service
service = Service(globals())

@service.xmlrpc
def add(a,b): return a+b

@service.xmlrpc
def sub(a,b): return a-b

def call(): return service()

def tester():
import xmlrpclib
server=xmlrpclib.ServerProxy('http://hostname:port/app/controller/call/xmlrpc')
return str(server.add(3,4)+server.sub(3,4))

Read more here