Está en la página 1de 58

Generalidades

Inicio
Web2py viene en paquetes binarios para Windows y Mac OS X. Tambin hay una versin de cdigo fuente que se ejecuta en Windows, Mac, Linux y otros sistemas Unix. Las versiones Windows y OS X binarias incluyen el necesario intrprete de Python. El paquete del cdigo fuente de Python asume que este ya est instalado en el equipo. Web2py no requiere instalacin. Para empezar, descomprimir el archivo zip descargado para su sistema operativo y ejecutar el archivo web2py correspondiente. En Windows, ejecute:

web2py.exe

En OS X, ejecute:

open web2py.app
En Unix y Linux, ejecute desde la fuente tipeando:

python2.5 web2py.py
El programa web2py acepta varias opciones de lnea de comandos que se describen ms adelante. Por defecto, en el inicio, web2py muestra una ventana de inicio:

y luego muestra una aplicacin GUI que le pide elejir una contrasea de administrador una sola vez, la direccin IP de la interfaz de red que se utilizar para el servidor web y un nmero de puerto desde donde servir peticiones. Por defecto, web2py ejecuta su servidor web en 127.0.0.1:8000 (el puerto 8000 en localhost), pero se puede ejecutar en cualquier direccin IP y puerto disponible. Se puede consultar la direccin IP de su interfaz de red mediante la apertura de una lnea de comandos y escribir ipconfig en Windows o ifconfig en OS X y Linux. A partir de ahora suponemos que web2py se est ejecutando en localhost (127.0.0.1:8000). Se usa 0.0.0.0:80 para ejecutar web2py pblicamente en cualquiera de las interfaces de red.

Si usted no proporciona una contrasea de administrador, la interfaz de administracin est deshabilitada. Esta es una medida de seguridad para evitar exponer pblicamente la interfaz admin. La interfaz administrativa, admin, slo es accesible desde localhost a menos que ejecute web2py soportando Apache con mod_proxy. Si admin detecta un proxy, la cookie de sesin se establece para bloquear y la entrada al sistema deadmin no funciona a menos que la comunicacin entre el cliente y el proxy vaya a travs de HTTPS, esto es una medida de seguridad. Todas las comunicaciones entre el cliente y admin siempre debe ser local o encriptadas, de lo contrario un atacante podra ser capaz de realizar un ataque de hombre-en-el-medio o un ataque de rplica y ejecutar cdigo arbitrario en el servidor. Despus de la contrasea de administracin se ha fijado, web2py pone en marcha el navegador de Internet en la pgina: http://127.0.0.1:8000/ Si el equipo no tiene un navegador por defecto, abra un navegador web e introduzca la direccin URL.

Haciendo click en administrative interface lleva a la pgina de entrada al sistema para la interface de administracin.

La contrasea del administrador es la contrasea elegida en el inicio. Se toma en cuenta que slo hay un administrador, por lo que slo hay una contrasea de administrador. Por razones de seguridad, al desarrollador se le pide que elija una contrasea nueva cada vez que se inicia web2py a menos que la opcin <recycle> se especifique. Esto es distinto del mecanismo de autenticacin de aplicaciones en web2py. Despus de que el administrador inicia sesin en web2py, el navegador es redirigido al sitio de la pgina.

Esta pgina muestra todas las aplicaciones instaladas en web2py y permite al administrador gestionarlas. web2py viene con tres aplicaciones:

Una aplicacin de admin, la que seest usando en este momento. Una aplicacin de ejemplos (examples), con la documentacin en lnea interactiva y una rplica de la pgina web oficial de web2py. Una aplicacin de bienvenida (welcome). Este es el modelo bsico para cualquier aplicacin web2py otros. Esta es llamada la aplicacin de andamios. Esta es tambin la aplicacin que da la bienvenida a un usuario en el inicio.

Las aplicaciones listas para usar son llamadas dispositivos web2py. Se pueden descargar muchos dispositivos disponible libremente desde 34. Los usuarios de web2py son incentivados a inscribir nuevos dispositivos, ya sea en cdigo abierto o en cdigo cerrado (ya compilado y empaquetado).

Desde la pgina de la aplicacin admin, se pueden realizar las siguientes operaciones:

Instalar (install) una aplicacin completando el formulario en la parte inferior derecha de la pgina. Asigne un nombre a la aplicacin, seleccione el archivo que contiene una aplicacin empaquetada o la URL donde se encuentra la aplicacin, y haga clic en enviar (submit). Desinstalar (uninstall) una aplicacin haciendo clic en el botn correspondiente. Hay una pgina de confirmacin. Crear (create) una nueva aplicacin eligiendo un nombre y haciendo clic en enviar (submit). Empaquetar (package) una aplicacin para su distribucin haciendo clic en el botn correspondiente. Una aplicacin de descarga es un archivo tar que contiene todo, incluyendo la base de datos. Usted no debe descomprimir este archivo; web2py lo hace automticamente cuando se instalan con admin. Limpieza de archivos temporales (clean up) de una aplicacin tales como sesiones, errores y los archivos cach. Editar (EDIT) una aplicacin. Al crear una nueva solicitud usando admin, esta comienza como un clon de la aplicacin de andamio welcome con un model/db.py que crea una base de datos SQLite, se conecta a ella, crea instancias de Auth, Crud y Servicio, y los configura. Tambin proporciona un controller/ default.py, que expone las acciones ndice (index), descargar (download), usuario (user) para la gestin de usuarios, y llamada (call) para los servicios. A continuacin, se supone que estos archivos se han eliminado, vamos a estar creando aplicaciones desde cero.

Diga Hello
Aqu, como ejemplo, se crea una sencilla aplicacin web que muestra el mensaje Hello from MyApp al usuario. Vamos a llamar a esta aplicacin myapl. Tambin vamos a agregar un contador que cuenta las veces que el usuario visita la pgina. Se puede crear una nueva aplicacin con slo escribir su nombre en la forma de la parte superior derecha de la pgina web de admin.

Despus de presionar enviar [submit], la aplicacin es creada como una copia de la applicacin incorporada welcome.

Para ejecutar la aplicacin nueva se debe visitar: http://127.0.0.1:8000/myapp Ahora se tiene una copia de la aplicacin welcome. Para editar una aplicacin, hacer clic en el botn edit para al aplicacin creada recientemente.

La pgina EDIT dice qu est dentro de la aplicacin. Cada aplicacin web2py consta de ciertos archivos, la mayora de los cuales pertenecen a una de estas cinco categoras:

Modelos (models): describen la representacin de datos. Controladores (controllers): describen la lgica de la aplicacin y flujo de trabajo. Vistas (views): describen la presentacin de datos. Idiomas (languages): describen la manera de trasladar la presentacin de solicitud a otros idiomas. Mdulos (modules): mdulos de Python que pertenecen a la aplicacin. Archivos Estticos (static files): imgenes estticas, archivos CSS, archivos JavaScript, etc

Todo est cuidadosamente organizado basado en el patrn de diseo Modelo-Vista-Controlador. Cada seccin en la pgina edit corresponde a una subcarpeta en la carpeta de la aplicacin. Hay que tomar en cuenta que los ttulos de las secciones se conmutan segn el contenido. Los nombres de carpeta en archivos estticos tambin son plegables. Cada archivo enumerado en la seccin corresponde a un archivo ubicado fsicamente en la subcarpeta. Cualquier operacin que se realiza en un archivo a travs de la interfaz de admin (crear, editar, eliminar) se puede realizar directamente desde el intrprete de comandos usando cualquier editor.

La aplicacin contiene otros tipos de archivos (base de datos, archivos de sesin, los archivos de error, etc), pero que no figuran en la pgina edit, porque no son creados o modificados por el administrador, sino que son creados y modificados por la propia aplicacin. Los controladores contienen la lgica y el flujo de trabajo de la aplicacin. Cada direccin URL se designa en una llamada a una de las funciones de los controladores (acciones). Hay dos controladores por defecto: appadmin.py y default.py. appadmin proporciona un interfaz con la administracin de la base de datos, no lo necesitamos en este momento. default.py es el controlador necesario para editar, el que se llama por defecto cuando no se especifica ningn controlador en la URL. Editar el index funciona de la siguiente manera:

1 2

def index(): return "Hello from MyApp"

Aqui se ve como el editor en lnea luce:

Salvmoslo y regresemos a la pgina edit. Clic en el enlac del ndice para visitar la pgina que ha sido creada. Cuando se visita la URL http://127.0.0.1:8000/myapp/default/index

la accin del index en el controlador por defecto de myappl es llamada. Este retorna una cadena que el brownser despliega para que se vea. Debe lucir as:

Ahora, se edita la funcinndx tal como sigue:

1 2

def index(): return dict(message="Hello from MyApp")

Tambin, desde la pgina edit, se edita la vista default/index (el nuevo archivo asociado con la accin), y en este archivo, se escribe:

1 2 3 4 5 6

<html> <head></head> <body> <h1>{{=message}}</h1> </body> </html>

Ahora la funcin retorna un diccionario definiendo un mensaje (message). Cuando una accin retorna un diccionario, web2py busca una vista con el nombre

[controller]/[function].[extension]
y lo ejecuta. Aqu [extension] es la prrroga solicitada. Si no se especifica la extensin, el valor predeterminado es html, y eso es lo que vamos a asumir aqu. Bajo este supuesto, la vista es un archivo HTML que se incluye en el cdigo Python usando etiquetas especiales {{}}. En particular, en el ejemplo, el {{=message}} instruye web2py para reemplazar el cdigo marcado con el valor de message devuelto por la accin. Ntese que aqu message no es una palabra clave de web2py sino que se define en la accin. Hasta ahora no hemos utilizado ninguna palabra clave web2py. Si web2py no encuentra la vista solicitada, utiliza la vista generic.html que viene con cada aplicacin.

Si otra extensin distinta que html se especifica (json, por ejemplo), y el archivo vista de [controlador] / [funcin]. json no se encuentra, web2py busca la vista generic.json. web2py viene con generic.html, generic.json, generic.xml y generic.rss. Estas vistas genricas puede ser modificadas para cada aplicacin individual, y vistas adicionales se pueden agregar fcilmente. Lea ms sobre este tema en el captulo 9. Si se vuelve a EDIT y se hace clic en el index, ahora veremos la siguiente pgina HTML:

Contemos
Ahora vamos a agregar un contador a esta pgina que contar cuntas veces el mismo visitante v la pgina. Web2py en forma automtica y transparente hace seguimiento de los visitantes usando sesiones y cookies. Por cada nuevo visitante, se crea una sesin y le asigna una nica session_id. La sesin es un contenedor para las variables que se almacenan en el servidor. El identificador nico se enva al navegador a travs de una cookie. Cuando el visitante solicita otra pgina desde la misma aplicacin, el navegador enva la cookie, se recuperar por web2py, y el correspondiente perodo de sesiones se restaura. Para utilizar el perodo de sesiones, se modifica el controlador por defecto:

1 2 3 4 5 6

def index(): if not session.counter: session.counter = 1 else: session.counter += 1 return dict(message="Hello from MyApp", counter=session.counter)

Observe que counter no es una palabra clave de web2py, pero session lo es. Le estamos pidiendo a web2py comprobar si existe una variable de contador en la sesin y, si no, que cree una y le asigne 1. Si el contador est ah, le pedimos a web2py aumentar el contador en 1. Finalmente pasamos el valor del contador a la vista. Una forma ms compacta de codificar la misma funcin es la siguiente:

1 2 3

def index(): session.counter = (session.counter or 0) + 1 return dict(message="Hello from MyApp", counter=session.counter)

Ahora modifque la vista para aadir una lnea que muestre el valor del contador:

1 2 3 4 5 6 7

<html> <head></head> <body> <h1>{{=message}}</h1> <h2>Number of visits: {{=counter}}</h2> </body> </html>

Cuando se visita la pgina index otra vez (y otra) se debe tener la siguiente pgina HTML:

El contador se asocia con cada visitante, y se incrementa cada vez que el visitante recarga la pgina. Diferentes visitantes ven diferentes contadores.

Di mi nombre
Ahora se crean dos pginas (first y second) donde la primera crea una forma, pregunta el nombre de quin la visita, y redirecciona a la segunda pgina, la cual saluda el visitante por su nombre.

Se escriben las acciones correspondientes en el controlador por defecto:

1 2 3 4

def first(): return dict() def second(): return dict()

Entonces se crea una vista default/first.html para la primera accin:

y se inserta:

1 2 3 4 5 6

{{extend 'layout.html'}} What is your name? <form action="second"> <input name="visitor_name" /> <input type="submit" /> </form>

Finalmente se crea una vista default/second.html para la segunda accin:

1 2

{{extend 'layout.html'}} <h1>Hello {{=request.vars.visitor_name}}</h1>

En el diseo de ambas vistas, hemos ampliado la la vista bsica layout.html que viene con web2py. La vista de diseo mantiene el aspecto de las dos pginas coherente. El archivo de diseo se puede editar y volver a montarse fcilmente, ya que principalmente contiene cdigo HTML. Si ahora se visita la primera pgina, al escribir su nombre:

y enviar la forma, se recibir el saludo:

Postbacks (restitucin de datos)


El mecanismo para el envo de formas que utilizamos antes es muy comn, pero no es una buena prctica de programacin. Todas las entradas deben ser validadas y, en el ejemplo anterior, la carga de validacin caera en la segunda accin. As, la accin que realiza la validacin es diferente de la accin que gener el formulario. Esto tiende a provocar redundancia en el cdigo.

Un mejor modelo para el envo de la forma es enviar los formularios a la misma accin que los genera, en nuestro ejemplo, la first. La accin first debe recibir las variables, procesarlas, almacenarlas en el servidor, y redirigir al visitante a la segunda pgina, que recupera las variables. Este mecanismo se llama restitucin de datos - postback.

Se modifica el controlador por defecto para implementar la auto-presentacin:

1 2 3 4 5 6 7 8

def first(): if request.vars.visitor_name: session.visitor_name = request.vars.visitor_name redirect(URL('second')) return dict() def second(): return dict()

Luego se modifica la vista default/first.html:

1 2 3 4 5 6

{{extend 'layout.html'}} What is your name? <form> <input name="visitor_name" /> <input type="submit" /> </form>

Y la vista default/second.htmlnecesita recuperar los datos de la session en lugar que desde request.vars:

1 2

{{extend 'layout.html'}} <h1>Hello {{=session.visitor_name or "anonymous"}}</h1>

Desde el punto de vista del visitante, la auto-presentacin se comporta exactamente igual que en la implementacin anterior. No hemos aadido la validacin todava, pero ahora est claro que la validacin debe ser realizada por la primera accin. Este enfoque tambin es mejor porque el nombre del visitante permanece la sesin, y se puede acceder por todas las acciones y vistas en las aplicaciones sin tener que ser pasado a ellas de forma explcita. Tenga en cuenta que si la second accin se llama alguna vez antes de que un nombre de visitante se coloque, se ver en pantalla Hello anonymous porque session.visitor_name retorna None. Tambin podramos agregar el siguiente cdigo en el controlador (dentro de la funcin second):

1 2

if not request.function=='first' and not session.visitor_name: redirect(URL('first'))

Se trata de un mecanismo general que puede utilizar para hacer cumplir la autorizacin en los controladores, aunque debe verse el Captulo 8 para un mtodo ms poderoso. Con web2py podemos avanzar un paco ms y pedirle que genere la forma por nosotros, incluyendo la validacin. web2py provee ayudas (FORM, INPUT, TEXTAREA y SELECT/OPTION) con los mismos nombres equivalentes a etiquetas HTML. Pueden ser utilizados para construir las formas, ya sea en el controlador o en la vista. Por ejemplo, aqu hay una forma posible de reescribir la primera accin:

1 2 3 4 5 6 7

def first(): form = FORM(INPUT(_name='visitor_name', requires=IS_NOT_EMPTY()), INPUT(_type='submit')) if form.accepts(request.vars, session): session.visitor_name = form.vars.visitor_name redirect(URL('second')) return dict(form=form)

donde se dice que la FORM etiqueta contiene dos etiquetas INPUT. Los atributos de las etiquetas de entrada son especificados por los argumentos nombrados a partir de subrayado. El argumento requires no es un atributo de etiqueta (porque no comienza con subrayado) pero establece un validador para el valor de visitor_name. El objeto form puede ser fcilmente serializado en HTML insertndolo en la vista default/first.html.

1 2 3

{{extend 'layout.html'}} What is your name? {{=form}}

El mtodo form.accepts aplica los validadores. Si el formulario de auto-presentacin es validado, este almacena las variables de la sesin y las restituye como antes. Si el formulario no pasa la validacin, los mensajes de error se insertan en el formulario y se muestran al usuario, como a continuacin:

En la siguiente seccin vamos a mostrar cmo las formas se pueden generar automticamente a partir de un modelo.

Un Blog Image
Aqu, como otro ejemplo, queremos crear una aplicacin web que permita al administrador colocar imgenes y darles un nombre, y permite que los visitantes del sitio web ver las imgenes con nombre y enviar comentarios. Al igual que antes, se crea la nueva aplicacin desde la pgina web de admin y se navega a la pgina de edit:

Comenzamos creando un modelo, una representacin de los datos persistentes en la aplicacin (las imgenes a subir, sus nombres, y los comentarios). Primero, se necesita crear/editar un archivo modelo que, por falta de imaginacin, llamamos db.py. Asumimos que el cdigo que se v abajo, reemplazar cualquier cdigo existente en db.py. Modelos y controladores deben tener una extensin .py ya que son cdigo Python. Si la extensin no se provee, web2py la incluye. Vistas, en cambio tienen una extensin .html ya que principalmente contienen cdigo HTML. Se edita el archivodb.py haciendo clic en el correspondiente botn editar:

Y se inserta lo siguiente:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

db = DAL("sqlite://storage.sqlite") db.define_table('image', Field('title'), Field('file', 'upload')) db.define_table('comment', Field('image_id', db.image), Field('author'), Field('email'), Field('body', 'text')) db.image.title.requires = IS_NOT_IN_DB(db, db.image.title) db.comment.image_id.requires = IS_IN_DB(db, db.image.id, '%(title)s') db.comment.author.requires = IS_NOT_EMPTY() db.comment.email.requires = IS_EMAIL() db.comment.body.requires = IS_NOT_EMPTY() db.comment.image_id.writable = db.comment.image_id.readable = False

Analizemos esto lnea a lnea:

Lnea1 defines una variable global llamada db que representa la connecin a la base de datos. En este caso es una coneccin a una base de datos SQLite guardada en el archivo applications/images/databases/storage.sqlite. En el caso de SQLite, si la base de datos no existe, se crea. Se puede cambiar el nombre del archivo, asi como el de la variable global db, pero es conveniente darles el mismo nombre, para hacerlo fcl de recordar. Lneas 3-5 definen la tabla image. define_table es un mtodo del objeto db. El primer argumento, imagees el nombre de la tabla que estamos definiendo. Los otros argumentos son los campos pertenecientes a la tabla. Esta tabla tiene un campo llamado title, un campo llamado file, y un campo llamado id que sirve como clave primaria de la tabla (id no se declara explcitamente porque todas las tablas tienen un campo id por defecto). El campo field es una cadena, y el campo file es del tipo upload. upload es un tipo especial de campo usado por la capa de abstracin de datos (DAL) para guardar los nombres de archivos que se han bajado. web2py sabe como bajar archivos (via streaming en caso de que sean muy largos), renombrarlos en forma segura y guardarlos. Cuando una tabla se define, web2py toma una de varias acciones posibles: a) si la tabla no existe, se crea la tabla; b) si la tabla existe y no se corresponde con la definicin, se altera como corresponde, y si un campo tiene un tipo diferente, web2py intenta convertir su contenido, c) si la tabla existe y corresponde a la definicin, web2py no hace nada. Este comportamiento se denomina migracin. En web2py las migraciones son automticas, pero se puede desactivar para cada tabla pasando migrate=False como el ltimo argumento de define_table. Lneas 7-11 define otra tabla llamada coment. Un comentario tiene un author, un email (tenemos la intencin de almacenar la direccin de correo electrnico del autor del comentario), un body de tipo text (tenemos la intencin de usarlo para almacenar en el comentario publicado por el autor), y un campoimage_id de tipo de referencia que apunta a db.image a travs del campoid. En las lnea 13 db.image.title representa el campo title de la tabla image. El atributo requires le permite establecer los requisitos/limitaciones que sern reforzadas por las formas web2py. Aqu es necesario que el title sea nico.

IS_NOT_IN_DB(db, db.image.title)

Los objetos que representan a esas limitaciones se llaman validadores. Validadores mltiples pueden agruparse en una lista. Los validadores se ejecutan en el orden en que aparecen. IS_NOT_IN_DB(a, b) es un validador especial que comprueba que el valor de b para un nuevo registro, no aparece ya en a. La lnea 14 requiere que el campo image_id de la tabla coment est en db.image.id. En cuanto a la base datos se refiere, que ya haba declarado esto cuando se defini la tabla coment. Ahora le estamos diciendo forma explcita al modelo que esta condicin debe ser reforzada por web2py, tambin, a nivel de procesamiento formas cuando un nuevo comentario sea publicado, de modo que los valores no vlidos no se propagan a partir formas de entrada a la base de datos. Tambin se requiere que el image_id est representado por title, %(title)s, del registro correspondiente. de de de de el

La lnea 18 indica que el campo image_id del cuadro coment no debe ser mostrado en las formas, writable=False y ni siquiera en las formas de slo lectura, readable=False. El significado de los validadores en las lneas 15-17 debera ser obvio. Note que el validado

db.comment.image_id.requires = IS_IN_DB(db, db.image.id, '%(title)s')

Puede omitirse (lo cual sera automtico) si fueramos a especificar un formato para representar una imagen:

db.define_table('image',....,format='%(title)s')
donde el formato puede ser una cadeba o una funcin que toma un registro y retorna una cadena. Una vez que se define el model, si no hay errores, web2py cre una interface de administracin de la aplicacin para manejar la base de datos. Se accede a travs de el enlace database administration en la pgina edit o de forma directa: http://127.0.0.1:8000/images/appadmin Aqui una vista de la pantalla de la interface appadmin:

Esta interfaz se codifica en el controlador llamado appadmin.py y la vista correspondiente appadmin.html. De ahora en adelante, nos referiremos a esta interfaz simplemente como appadmin. Esta permite al administrador de base de datos insertar nuevos registros, editar y borrar los registros existentes, consultar tablas, y enlazar bases de datos. La primera vez que appadmin se accesa, el modelo se ejecuta y se crean las tablas. El DAL de web2py traduce el cdigo Python en instrucciones SQL que son especficas del motor interno de la base de datos seleccionada, (SQLite en este ejemplo). Se puede ver el SQL generado a partir de la pgina de edicin haciendo clic en el sql.log bajo la seccin models. Observese que el vnculo no est presente hasta que las tablas se han creado.

Si se fuera a editar el modelo y accesar appadmin otra vez, web2py podra general SQL para alterar las tablas existentes. El SQL generado se registra en sql.log. Ahora, de regreso a appadmin y tratando de insertar un nuevo registro de imagen:

web2py ha traducido el campo upload de db.image.file en una forma de carga para el archivo. Cuando se enva la forma y un archivo de imagen se carga, el archivo se renombra de un modo seguro que preserve la extensin, se guarda con el nuevo nombre en la carpeta de la aplicacin uploads, y el nuevo nombre se almacena en campo db.image.file. Este proceso est diseado para prevenir ataques de directorio transversal. Ntese que cada tipo de campo se representa por un widget. Widgets por defecto se puede reemplazar. Al hacer clic en un nombre de tabla en appadmin, web2py realiza una seleccin de todos los registros en la tabla actual, identificados por un query del DAL

db.image.id > 0

Y d el resultado.

Se puede seleccionar un conjunto diferente de registros editando el query SQL y presionando apply. Para editar o borrar un simple registro, se le d clic al numero id del registro.

A causa del validador IS_IN_DB el campo de referencia image_id es presentado en un men drop-down. Los items en el men drop-down son guardados como claves (db.image.id), pero son representados por su db.image.title, tal como se ha especificado por el validador. Validadores son poderosos objetos que saben como representar campos, filtrar valores de campos, generar errores y formatear valores extrados de el campo. La siguiente figura muestra que ocurre cuando se enva una froma que no pasa la validacin:

Las mismas formas que se generan automticamente por appadmin tambin se puede generar mediante programacin a travs del SQLFORM helper que est integrado en las aplicaciones de usuario. Estas formas son amigables con CSS de usar, y puede ser personalizadas. Cada aplicacin tiene su propia appadmin, por lo que la appadmin misma puede ser modificada sin afectar a otras aplicaciones. Hasta ahora, la aplicacin sabe cmo almacenar los datos, y hemos visto cmo acceder a la base de datos a travs de appadmin. El acceso a appadmin est restringido al administrador, y no pretende ser una interfaz web para la aplicacin de produccin, de ah la siguiente parte de este camino. En concreto queremos crear:

Una pgina index que muestre todas las imgenes disponibles ordenadas por ttulos y enlaces a pginas de detalles de las imgenes. Una pgina show/[id] pgina que le muestra al visitante la imagen solicitada y permite al visitante ver y enviar comentarios. Una accin download/[name] para descargar las imgenes subidas.

Esto se representa esquemticamente aqui:

Se regresa a la pgina edit y se edita el controlador default.py, reemplazando su contenido por lo siguiente:

1 2 3

def index(): images = db().select(db.image.ALL, orderby=db.image.title) return dict(images=images)

Esta accin devuelve un diccionario. Las claves de los elementos en el diccionario se interpretan como variables pasadas a la vista asociada a la accin. Si no hay vista, la accin se representa por la vista generic.html que se entrega con todas las aplicaciones web2py. La accin index realiza una seleccin de todos los campos (db.image.ALL) de todos los campos de la tabla imagen ordenados por db.image.title. El resultado de la seleccin es un objeto Rows que contiene los registros. Asignar esto a una variable local llamada images devuelta por la accin a la vista. Images es iterativa y sus elementos son las filas seleccionadas. Para cada fila, las columnas se puede acceder como diccionarios: images[0][title] o, equivalentemente, como images[0].title. Si no se disea una vista, el diccionario es traducido por views/generic.htmly una llamada a la accin index se vera as:

Todava no ha creado una vista para esta accin, sin embargo, web2py ofrece el conjunto de registros en forma de tabla sin formato. Se procede a crear una vista para la accin index. Se vuelve a admin, se edita default/index.html y se reemplaza su contenido con lo siguiente:

1 2 3 4 5 6 7

{{extend 'layout.html'}} <h1>Current Images</h1> <ul> {{for image in images:}} {{=LI(A(image.title, _href=URL("show", args=image.id)))}} {{pass}} </ul>

La primera observacin es que esta perspectiva es HTML puro, con etiquetas especiales {{...}}. El cdigo insertado en {{...}} es puro cdigo Python con una advertencia: el sangrado es irrelevante. Los bloques de cdigo comienzan con las lneas que terminan en dos puntos (:) y terminan en las lneas que empiezan con la palabra clave pass. En algunos casos, el final de un bloque es evidente por el contexto y el uso de pass no es obligatorio. Lneas 5-7 ciclo sobre las filas de imgenes y para cada fila de visualizacin de la imagen:

LI(A(image.title, _href=URL('show', args=image.id))


Esta es una etiqueta <li>...</li> que contiene una etiqueta <a href=...>...</a> la cual contiene contiene la image.title. El valor de la referencia de hipertexto (atributo href) es:

URL('show', args=image.id)

es decir, la direccin URL dentro de la misma aplicacin y controlador segn la solicitud actual que llama a la funcin llamada show, pasando un solo argumento a la funcin, args=image.id. LI, A, etc. son web2py helpers que se asignan a las correspondientes etiquetas HTML. Sus argumentos sin nombre se interpretan como objetos a serializar y se incluirn en innerHTML de la etiqueta. Argumentos con nombre que comienzan con un guin abajo (por ejemplo _href) se interpretan como atributos de la etiqueta, pero sin el carcter de subrayado. Por ejemplo _href es el atributo href, _class es el atributo class, etc. Como ejemplo, la siguiente declaracin:

{{=LI(A('something', _href=URL('show', args=123))}}


Se ofrece como:

<li><a href="/images/default/show/123">something</a></li>

Un montn de helpers (INPUT, TEXTAREA, OPTION y SELECT) tambin soportan algunos atributos con nombres especiales que no comienzan con subrayado (value, y requires). Ellos son importantes para construir formas especficas que y sern discutidos despus. Se regresa a la pgina edit. Esta ahora indica que default.py exposes index. Si se le da clic a index, se puede visitar la nueva pgina creada: http://127.0.0.1:8000/images/default/index la cual se ve:

Si se le d clic en el enlace de el nombre de la imagen, se redirecciona a: http://127.0.0.1:8000/images/default/show/1 Y esto produce un error, dado que no se ha creado todava una accin llamada show en el controlador default.py. Editemos el controlador default.py y reemplacemos su contenido con:

1 2 3 4 5 6 7 8 9 10 11 12 13

def index(): images = db().select(db.image.ALL, orderby=db.image.title) return dict(images=images) def show(): image = db(db.image.id==request.args(0)).select().first() form = SQLFORM(db.comment) form.vars.image_id = image.id if form.accepts(request.vars, session): response.flash = 'your comment is posted' comments = db(db.comment.image_id==image.id).select() return dict(image=image, comments=comments, form=form) def download(): return response.download(request, db)

El controlador contiene dos acciones: show y download. La accin showselecciona la imagen con el id analizado por los agumentos del requerimiento y todo los comentarios relacionados con la imagen. show, entonces, pasa todo a la vista default/show.html. La imagen id referenciada por:

URL('show', args=image.id)

En default/index.html, puede ser accedida como: request.args(0) desde la accin show. La accindownload espera un nombre de archivo en request.args(0), construye una ruta a la ubicacin donde se supone que ese archivo debe estar, y lo enva de vuelta al cliente. Si el archivo es demasiado grande, se transmite el archivo sin incurrir en ninguna sobrecarga de la memoria. Note las siguientes declaraciones:

La lnea 7 crea una forma SQLFORM de insercin para la tabla db.comment usando slo los campos especificados. La lnea 8 establece el valor por el campo de referencia, este no forma parte de la forma de entrada, ya que no est en la lista de los campos especificados arriba. Lnea 9 procesa la forma enviada (las variables de la forma enviadas estn en en request.vars) en la sesin actual (la sesin se utiliza para evitar duplicaciones, y para reforzar la navegacin). Si las variables de la forma presentada son validos, el nuevo comentario se aade en la tabla db.comment, de lo contrario la forma se modifica para incluir mensajes de error (por ejemplo, si la direccin de correo electrnico del autor no es vlida). !Todo esto se hace en la lnea 9!. La lnea 10 slo se ejecuta si la forma es aceptada, despus de que el registro se inserta en la tabla de base de datos. response.flash es una variable web2py que se muestra en las vistas y se utiliza para notificar al usuario de que algo pas. La lnea 11 selecciona todos los comentarios que hacen referencia a la imagen actual. La accin download que ya se ha definido en el controlador default.py de la aplicacin de andamiaje.

La accin download no devuelve un diccionario, por lo que no necesita un punto de vista. La accin show, sin embargo, debe tener una vista, por lo que se regresasa a admin a crear una nueva vista llamada default/show.html. Editar este nuevo archivo y reemplazar su contenido con el texto siguiente:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

{{extend 'layout.html'}} <h1>Image: {{=image.title}}</h1> <center> <img width="200px" src="{{=URL('download', args=image.file)}}" /> </center> {{if len(comments):}} <h2>Comments</h2><br /><p> {{for comment in comments:}} <p>{{=comment.author}} says <i>{{=comment.body}}</i></p> {{pass}}</p> {{else:}} <h2>No comments posted yet</h2> {{pass}} <h2>Post a comment</h2> {{=form}}

Esta vista despliega la image.file llamando la accin downloaddentro de la etiqueta <img ... /> . Si hay comentarios, se hace un ciclo sobre ellos para que cada uno sea visto. Aqui est como todo aparecer para el visitante:

Cuando un visitante enva un comentario usando esta pgina, el comentario se guarda en la base de datos y se agrega al final de la pgina.

Agregando CRUD
web2py tambin provee una CRUD API (Crear/Leer/Actualizar/Borrar por su acrnimo en ingls) que simplifica las formas an mas. Par usar CRUD es necesario definirlo en alguna parte, tal como en el mdulo db.py:

1 2

from gluon.tools import Crud crud = Crud(globals(), db)

Estas dos lneas estn ya en la aplicacin de andamiaje. El objeto crud provee mtodos de alto nivel, por ejemplo:

form = crud.create(table)

Y puede ser usado para reemplazar el patrn de programacin:

1 2 3 4

form = SQLFORM(table) if form.accepts(request.post_vars,session): session.flash = '...' redirect('...')

Aqui, se reescribe la accin showprevia usando crud y haciendo algunas mejoras:

1 2 3 4 5 6 7 8

def show(): image = db.image(request.args(0)) or redirect(URL('index')) db.comment.image_id.default = image.id form = crud.create(db.comment, message='your comment is posted', next=URL(args=image.id)) comments = db(db.comment.image_id==image.id).select() return dict(image=image, comments=comments, form=form)

Observerse, en principio que se ha usado la sintxis:

db.image(request.args(0)) or redirect(...)

Para traer el registro requerido. Ya que table(id) no retorna nada si el registro no se encuentra, se puede usar or redirect(...) en este caso en una lnea. El argumento next de crud.create es la URL a la que se redirecciona despus que la forma es aceptada. El argumento message es aquel que se ver luego de la aceptacin. Puede leerse mas sobre CRUD en el captulo 7.

Agregando autentificacin
La aplicacin API web2py para Control de Acceso basado en Roles es bastante sofisticada, pero por ahora nos limitaremos a restringir acceso a la accin show a usuarios autentificados, difiriendo una discusin mas detallada para el Captulo 8. Para limitar el acceso a usuarios autorizados, se necesitan completar tres pasos. En un modelo, por ejemplo db.py, necesita aadirse:

1 2 3

from gluon.tools import Auth auth = Auth(globals(), db) auth.define_tables()

En nuestro controlador, se necesita agregar una accin:

1 2

def user(): return dict(form=auth())

Esto es suficiente para permitir la entrada al sistema, registrarse, salir del sistema, etc. El diseo por defecto tambin nos mostrar opciones a las pginas correspondientes en la esquina superior derecha.

Las funciones que se quieren restringir pueden ahora decorarse, por ejemplo

@auth.requires_login() def show(): image = db.image(request.args(0)) or redirect(URL('index')) db.comment.image_id.default = image.id form = crud.create(db.comment, next=URL(args=image.id), message='your comment is posted') comments = db(db.comment.image_id==image.id).select() return dict(image=image, comments=comments, form=form)
Cualquier intento para accesar: http://127.0.0.1:8000/images/default/show/[image_id] requerira una entrada al sistema. Si el usuario no ha entrado al sistema, se ver redireccionado a http://127.0.0.1:8000/images/default/user/login

La funcin user tambin expone, entre otras las siguientes acciones: http://127.0.0.1:8000/images/default/user/logout http://127.0.0.1:8000/images/default/user/register http://127.0.0.1:8000/images/default/user/profile http://127.0.0.1:8000/images/default/user/change_password http://127.0.0.1:8000/images/default/user/request_reset_password http://127.0.0.1:8000/images/default/user/retrieve_username http://127.0.0.1:8000/images/default/user/retrieve_password http://127.0.0.1:8000/images/default/user/verify_email http://127.0.0.1:8000/images/default/user/impersonate http://127.0.0.1:8000/images/default/user/not_authorized

Ahora, un usuario que visita por primera vez necesita registrarse para poder entrar al sistema y leer o agregar comentarios. Ambos, el objeto auth y la funcin user estn ya definidos en la aplicacin de andamiaje. El objeto auth es altamente personalizable y puede manejar verificacin de email, aprobar el registro, CAPTCHA, y alternar mtodos de entrada a travs de plugins.

Configurando el diseo
Se puede configurar el diseo por defecto editando views/layout.html, pero puede configurarse tambin sin editarse el HTML. De hecho, la hoja de estilo static/base.css est bien documentada y descrita en el Captulo 5. Se pueden cambiar el color, las columnas, el tamao, los bordes, el fondo sin editar el HTML. Si se quiere editar el men, el ttulo o el subttulo, esto puede hacerse en cualquiera de los archivos model. La app andamio, determina valores por defecto de estos parmetros en el archivo models/menu.py:

1 2 3 4 5 6

response.title = request.application response.subtitle = T('customize me!') response.meta.author = 'you' response.meta.description = 'describe your app' response.meta.keywords = 'bla bla bla' response.menu = [ [ 'Index', False, URL('index') ] ]

Un Wiki
En esta seccin, se construye un wiki, a partir de cero y sin utilizar la funcionalidad extendida proporcionada por el plugin_wiki que se describe en el captulo 13. El visitante podr crear pginas, buscar en ellas (por ttulo), y editarlas. El visitante tambin podr enviar comentarios (exactamente como en las aplicaciones anteriores), as como publicar documentos (como archivos adjuntos a las pginas) y vincularlos a ellas. Por convenio, se adopta la sintaxis Markmin de nuestra sintaxis wiki. Se implementar tambin una pgina de bsqueda con Ajax, un feed RSS para las pginas, y un manejador para buscar las pginas a travs de XML-RPC 46. El diagrama siguiente, enumera las acciones que se necesitan para implementar y los enlaces que se intentan construir entre ellos.

Se comienza creando una nueva aplicacin andamio llamada mywiki.

El modelo debe contener tres tablas: page (pgina), comment (comentario) y document (documento). Tanto comment como document referenciam page porque pertenecen a ella. Un documento contiene un campo archivo del tipo upload como en la aplicacion images anterior. Aqui el modelo completo:

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

db = DAL('sqlite://storage.sqlite') from gluon.tools import * auth = Auth(globals(),db) auth.define_tables() crud = Crud(globals(),db) db.define_table('page', Field('title'), Field('body', 'text'), Field('created_on', 'datetime', default=request.now), Field('created_by', db.auth_user, default=auth.user_id), format='%(title)s') db.define_table('comment', Field('page_id', db.page), Field('body', 'text'), Field('created_on', 'datetime', default=request.now), Field('created_by', db.auth_user, default=auth.user_id)) db.define_table('document', Field('page_id', db.page), Field('name'), Field('file', 'upload'), Field('created_on', 'datetime', default=request.now), Field('created_by', db.auth_user, default=auth.user_id), format='%(name)s') db.page.title.requires = IS_NOT_IN_DB(db, 'page.title') db.page.body.requires = IS_NOT_EMPTY() db.page.created_by.readable = db.page.created_by.writable = False db.page.created_on.readable = db.page.created_on.writable = False db.comment.body.requires = IS_NOT_EMPTY() db.comment.page_id.readable = db.comment.page_id.writable = False db.comment.created_by.readable = db.comment.created_by.writable = False db.comment.created_on.readable = db.comment.created_on.writable = False db.document.name.requires = IS_NOT_IN_DB(db, 'document.name') db.document.page_id.readable = db.document.page_id.writable = False db.document.created_by.readable = db.document.created_by.writable = False db.document.created_on.readable = db.document.created_on.writable = False

Se edita el controlador default.py y se crean las siguientes acciones:

index: lista de todas la pginas wiki create: publicar otra pgina wiki show: mostrar una pgina wiki y sus comentarios, anexar dichos comentarios edit: editar una pgina ya existente documents: manejar los documentos anexados a una pgina download: bajar un documento (igual que en ejemplo images) search: desplegar un cuadro de bsqueda, via travs de una llamada Ajax, retornar todos los ttulos que coincidan con los tipos del visitante.

bg_find: la funcin de llamada Ajax. Retorna el HTML que se inserta en la mquina de bsqueda mientras el visitante escribe.

Aqu el controlador default.py:

def index(): """ this controller returns a dictionary rendered by the view it lists all wiki pages >>> index().has_key('pages') True """ pages = db().select(db.page.id,db.page.title,orderby=db.page.title) return dict(pages=pages) @auth.requires_login() def create(): "creates a new empty wiki page" form = crud.create(db.page, next = URL('index')) return dict(form=form) def show(): "shows a wiki page" this_page = db.page(request.args(0)) or redirect(URL('index')) db.comment.page_id.default = this_page.id form = crud.create(db.comment) if auth.user else None pagecomments = db(db.comment.page_id==this_page.id).select() return dict(page=this_page, comments=pagecomments, form=form) @auth.requires_login() def edit(): "edit an existing wiki page" this_page = db.page(request.args(0)) or redirect(URL('index')) form = crud.update(db.page, this_page, next = URL('show', args=request.args)) return dict(form=form) @auth.requires_login() def documents(): "lists all documents attached to a certain page" this_page = db.page(request.args(0)) or redirect(URL('index')) db.document.page_id.default = this_page.id form = crud.create(db.document) pagedocuments = db(db.document.page_id==this_page.id).select() return dict(page=this_page, documents=pagedocuments, form=form) def user(): return dict(form=auth()) def download(): "allows downloading of documents" return response.download(request, db) def search(): "an ajax wiki search page" return dict(form=FORM(INPUT(_id='keyword',_name='keyword', _onkeyup="ajax('bg_find', ['keyword'], 'target');")), target_div=DIV(_id='target')) def bg_find(): "an ajax callback that returns a <ul> of links to wiki pages" pattern = '%' + request.vars.keyword.lower() + '%' pages = db(db.page.title.lower().like(pattern))\ .select(orderby=db.page.title) items = [A(row.title, _href=URL('show', args=row.id)) \

for row in pages] return UL(items).xml()


Las lneas 2-6 ofrecen un comentario de la accin index. Las lneas 4-5 dentro del comentario se interpretan en python como cdigo prueba (doctest). Las pruebas se pueden ejecutar a travs de la interfaz admin. En este caso las pruebas comprueban que la accin index se ejecuta sin errores. Las lneas 18, 27, 35 tratan de buscar un registro page con el id en request.args(0). Las lneas 13, 20 y 37 definen y procesan formas creadas, por una nueva pgina y un comentario nuevo adems de un nuevo documento, respectivamente. La lnea 28 define y procesa una formade actualizacin de una pgina wiki. Cierta magia que sucede en la lnea 51. El atributo onkeyup de la etiqueta INPUT keyword se define. Cada vez que el visitante suelta una tecla, el cdigo JavaScript insertado en el atributo onkeyup se ejecuta en el cliente. Aqu est el cdigo JavaScript:

ajax('bg_find', ['keyword'], 'target');


ajax es una funcin de JavaScript definida en el archivo web2py_ajax.html, que es incluida por el diseo por defecto layout.html. Esta toma tres parmetros: el URL de la accin que realiza la llamada sncrona (bg_find), una lista de los id de las variables que se enviar a la llamada ([keyword]), y el ID donde la respuesta tiene que ser insertada (target). Tan pronto como algo se escriba en el cuadro de bsqueda y se suelte una tecla, el cliente llama al servidor y enva el contenido del campo keyword, y, cuando el servidor responde, la respuesta est incrustada en la misma pgina como el innerHTML de la etiqueta target. La etiqueta target es una DIV definida en la lnea 52. Podra haber sido definida en la vista tambin. Aqu est el cdigo para la vista default/create.html:

1 2 3

{{extend 'layout.html'}} <h1>Create new wiki page</h1> {{=form}}

Si se visita la pgina create, se ver lo siguiente:

aqu el cdigo por la vista default/index.html:

1 2 3 4 5 6 7

{extend 'layout.html'}} <h1>Available wiki pages</h1> [ {{=A('search', _href=URL('search'))}} ]<br /> <ul>{{for page in pages:}} {{=LI(A(page.title, _href=URL('show', args=page.id)))}} {{pass}}</ul> [ {{=A('create page', _href=URL('create'))}} ]

Este genera la siguiente pgina:

aqu el cdigo para la vista default/show.html:

1 2 3 4 5 6 7 8 9 10 11 12 13

{{extend 'layout.html'}} <h1>{{=page.title}}</h1> [ {{=A('edit', _href=URL('edit', args=request.args))}} | {{=A('documents', _href=URL('documents', args=request.args))}} ]<br /> {{=MARKMIN(page.body)}} <h2>Comments</h2> {{for comment in comments:}} <p>{{=db.auth_user[comment.created_by].first_name}} on {{=comment.created_on}} says <I>{{=comment.body}}</i></p> {{pass}} <h2>Post a comment</h2> {{=form}}

Si se desea usar la sintaxis markdown en vez de la sintaxis markmin:

from gluon.contrib.markdown import WIKI

Y se usa el helper WIKI en lugar del MARKMIN. Alternativamente, puede escojerse aceptar HTML crudo en vez de sintaxis markmin. En este caso se reemplazara:

1
con:

{{=MARKMIN(page.body)}}

{{=XML(page.body)}}

(de tal forma que el XML no se escape, como es el comportamiento por defecto de web2py) Esto puede hacerse mejor con:

{{=XML(page.body, sanitize=True)}}

Asignando sanitize=True, se le dice a web2py que deje fugar etiquetas XML no seguras, tal como <script>, y asi prevenir vulnerabilidades XSS. Ahora si, desde la pgina index, se hace clic a un ttulo de pgina, puede verse lo que se ha creado:

aqu el cdigo por la vista default/edit.html:

1 2 3 4

{{extend 'layout.html'}} <h1>Edit wiki page</h1> [ {{=A('show', _href=URL('show', args=request.args))}} ]<br /> {{=form}}

Este genera una pgina que se ve casi igual a la pgina create. Aqu el cdigo de la vista default/documents.html:

1 2 3 4 5 6 7 8 9 10

{{extend 'layout.html'}} <h1>Documents for page: {{=page.title}}</h1> [ {{=A('show', _href=URL('show', args=request.args))}} ]<br /> <h2>Documents</h2> {{for document in documents:}} {{=A(document.name, _href=URL('download', args=document.file))}} <br /> {{pass}} <h2>Post a document</h2> {{=form}}

Si, desde la pgina show, se le d clic a documentos, se pueden manejar ahora los documentos anexados a la pgina.

Finalmente, este es el cdigo por la vista default/search.html:

1 2 3

{{extend 'layout.html'}} <h1>Search wiki pages</h1>

[ {{=A('listall', _href=URL('index'))}}]<br /> {{=form}}<br />{{=target_div}}

El cual genera la siguiente forma de bsqueda Ajax:

Se puede tambin tratar de llamar la accin directamente visitando, por ejemplo el siguiente URL: http://127.0.0.1:8000/mywiki/default/bg_find?keyword=wiki Si se mira en la pgina fuente, se v el HTML retornado por la llamada:

<ul><li><a href="/mywiki/default/show/4">I made a Wiki</a></li></ul>


porque web2py

Generar un feed RSS de las pginas almacenadas usando web2py es fcil incluye gluon.contrib.rss2. Solo hay que anexar la siguiente accin al controlador por defecto:

1 2 3 4 5 6 7 8 9 10

def news(): "generates rss feed form the wiki pages" pages = db().select(db.page.ALL, orderby=db.page.title) return dict( title = 'mywiki rss feed', link = 'http://127.0.0.1:8000/mywiki/default/index', description = 'mywiki news', created_on = request.now, items = [

11 12 13 14

dict(title = row.title, link = URL('show', args=row.id), description = MARKMIN(row.body).xml(), created_on = row.created_on ) for row in pages])

Y cuando se visita la pgina http://127.0.0.1:8000/mywiki/default/news.rss se ve el feed (la salida exacta depende del lector de feeds). Observe que el dict se convierte automticamente a RSS, gracias a la extensin .rss en el URL.

web2py tambin incluye feedparser para leer feeds de terceros.

Finalmente, agreguemos un manejador XML-RPC que permita buscar en el wiki a travs de programacin:

1 2 3 4 5 6 7 8 9 10

service=Service(globals()) @service.xmlrpc def find_by(keyword): "finds pages that contain keyword for XML-RPC" return db(db.page.title.lower().like('%' + keyword + '%'))\ .select().as_list() def call(): "exposes all registered services, including XML-RPC" return service()

Aqu el manejador simplemente publica (via XML-RCP), las funciones especificadas en la lista. En este caso, find_by. find_by no es una accin (porque toma un argumento). Esta busca la base de datos con .select() y luego extrae los registros como una lista con .response y retorna la lista. Aqu un ejemplo de como acceder el manejador XML-RCP desde un programa Python externo.

1 2 3 4 5

>>> import xmlrpclib >>> server = xmlrpclib.ServerProxy( 'http://127.0.0.1:8000/mywiki/default/call/xmlrpc') >>> for item in server.find_by('wiki'): print item.created_on, item.title

El manejador puede ser accedido desde muchos otros lenguajes de programacin que entienden XML-RCP, incluyendo C, C++, C# y Java.

Ms sobre admin
La interfaz administrativa provee funcionalidad adicional que revisamos brevemente a continuacin. site Est pgina lista todas las aplicaciones instaladas. Hay dos formas en el fondo. La primera de ellas permite crear una aplicacin nueva especificando su nombre. La segunda forma permite bajar una aplicacin existente bien sea de un archivo local o de un URL remoto. Cuando una aplicacin es bajada, es necesario especificar su nmbre. Este puede ser su nombre original, pero no necesariamente. Esto permite instalar mltiples copias de la misma aplicacin. Se puede tratar, por ejemplo, de bajar el sistema de administracin de contenido KPAX desde: http://web2py.com/appliances/default/download/app.source.221663266939.... Aplicaciones que han sido bajadas pueden ser archivos .tar (convencin vieja) y archivos .w2p (convencin nueva). Las ltimas son archivos gzipped tar. Se pueden descomprimir manualmente con tar zxvf [nombre del archivo] aunque esto nunca es necesario.

Despus de una descarga exitosa, web2py despliega la suma de control del archivo bajado. Puede usarse para verificar que la fila no se corrompi durante la descarga. El nombre KPAX aparecer en la lista de aplicaciones instaladas. Se hace clic en el nombre KPAX en admin para crearlo y correrlo.

Los archivos de aplicacin estn almacenados como archivos web2py (tar gzipped), pero la intencin no es que se compriman o no manualmente, web2py lo hace por u Por cada aplicacin el site permite:

Desinstalar la aplicacin.

Ir a la pgina about (leer abajo). edit (leer abajo). Ir a la pgina errors (leer abajo). Limpiar archivos temporales (archivos de sesiones, errores y cache.disk). Comprimir todo. Esto retorna un archivo tar que contiene una copia completa de la aplicacin. Se sugiere limpiar primero los archivos temporales antes de comprimir una aplicacin. Compilar la aplicacin. Si no hay errores, esta opcin compilar en bytecode todos los modelos, conroladores y vistas. Ya que las vistas pueden extenderse e incluir otras vistas en un rbol, antes de la compilacin bytecode, el rbol de la vista para cada controlador se colapsa en un solo archivo. El efecto neto es que una aplicacin compilada bytecode es mas rpida, porque no hay mas ms revisiones de formatos, o substituciones de cadenas ocurriendo en tiempo de ejecucin. Paquete compilado. Esta opcin solo est presente en aplicaciones compiladas bytecode. Permite empacar la aplicaciones in cdigo fuente para distribucin como cdigo cerrado. Observe que python (tal como otros lenguajes de programacin) puede tcnicamente ser descompilado; por lo tanto compilar no ofrece proteccin completa del cdigo fuente. Sin embargo, decompilar puede ser difcil e ilegal. Remover compilaciones.. Esto simplemente remueve los modelos, vistas y controladores compilados bytecode de la aplicacin. En caso de que la aplicacin haya sio empaquetad en cdigo fuente o disada en forma local, no hay peligro en remover los archivos compilados bytecode, la aplicacin seguir trabajando. Si la aplicacin fu instalada desde un archivi empaquetado compilado, esto no es muy seguro, porque no hay cdigo fuente a donde regresar, y la palicacin puede que no trabaje ms. Toda la funcionalidad disponible desde la pgina admin en web2py se puede acceder mediante programacin via API definidas en el mdulo gluon/admin.py. Simplemente abra un shell python e importe este mdulo.

about El tabulador about permite editar la descripcin de la aplicacin y su licencia. Estn son escritas respectivamente en los archivos ABOUT y LICENSE en la carpeta de aplicaciones.

Se puede usar la sintaxis MARKMIN, o gluon.contrib.markdown.WIKI para estos archivos tal como se describe en la referencia. 29 edit La pgina edit ha sido ya usada en este captulo. Aqu quiero sealar unas funcionalidades adicionales de esta pgina:

Al darle clic a un nombre de archivo, puede verse el contenido con la sintaxis resaltada.I Al darle clic a edit, el archivo puede editarse usando una interface de red.I Si se hace clic en delete, el archivo puede borrarse (permanentemente). Si se hace clic en test, web2py ejecutar pruebas. Estas pruebas son escritar por el desarrollador usando Python doctests, y cada funcin debe tener sus propias pruebas. Pueden agregarse archivos de lenguajes, buscar en la aplicacin todas las cadenas, y editar traducciones de cadenas a travs de la interface en la red. Si los archivos estticos estn organizados en carpetas y sub-carpetas, la jerarqua de carpetas puede ser alternada dndole clic a el nombre de la carpeta.

Esta imagen muestra la salida de la pgina de prueba para la aplicacin welcome.

La imagen de abajo muestra el tabulador de lenguajes para la aplicacin welcome.

La prxima imagen muestra comoe ditar un archivo de lenguaje, en este caso el lenguaje it (italiano) para la aplicacin welcome.

shell Al hacer clic en el enlace shell bajo el tabulador de controladores en edit, web2py abrir un shell Phyton basado en al red y ejecutar los modelos para la aplicacin siguiente. Este permitir hablar intercativamente con la aplicacin.

crontab Tambin, bajo el tabulador de los controladores en edit hay un enlace crontab. Al darle clic a este enlace ser posible editar el archivo crontab de web2py. Este sigue la misma sintaxis como el crontab unix pero no se basa en unix. De hecho, solo requiere web2py, y trabaja en Windows. Permite registrar acciones que necesitan ser ejecutadas en el fondo a horas programadas. Para mas informacin al respecto, ver el prximo captulo. errors Cuando se programa en web2py, inevitablemente se cometern errores y se introducirn bugs. Web2py ayuda de dos formas: 1) Permite crear pruebas por cada funcin que pueden ser ejecutadas en el browser desde la pgina edit; y 2) Cuando un error aparece solo, se emite un boleto al visitante y este error se registra. Se introduce a propsito un error en la aplicacin images, tal como se ve a continuacin:

1 2 3 4

def index(): images = db().select(db.image.ALL,orderby=db.image.title) 1/0 return dict(images=images)

Cuando se accede la accin index, se emite el siguiente boleto:

Solo el administrador puede acceder el boleto:

El boleto se muestra la ejecucin de las llamadas mas recientes, y el contenido del archivo que caus el problema. Si el error se produce en una vista, web2py muestra la vista conviertida de HTML en cdigo Python. Esto permite identificar fcilmente la estructura lgica del archivo. Tenga en cuenta que en todas partes donde admin muestra cdigo de sintaxis resaltado (por ejemplo, en los informes de errores, las palabras clave web2py se muestran en naranja). Si se hace clic en una palabra clave web2py, se le redirige a una pgina de documentacin sobre la palabra clave. Si usted fija la divisin por cero error en la accin index e introduce una en la vista index:

1 2 3 4 5 6 7 8

{{extend 'layout.html'}} <h1>Current Images</h1> <ul> {{for image in images:}} {{1/0}} {{=LI(A(image.title, _href=URL("show", args=image.id)))}} {{pass}}

</ul>
Se obtiene el siguiente boleto:

Se observa que web2py ha convertido la vista de HTML a un archivo Python, y el error descrito en el boleto se refiere al cdigo Python generado y NO a el archivo vista original. Se produce el siguiente boleto:

Esto puede parecer confuso al principio, pero en prctica hace la eliminacin de errores mas fcil, porque la sangra de Python resalta la estructura lgica del cdigo que se insert en las vistas. El cdigo se muestra en el fondo de la misma pgina. Todos los boletos se listan bajo admin en la pgina errors para cada aplicacin:

Mercurial Si se est ejecutando de la fuente y se tiene la versin Mercurial de las libreras de control instalada:

easy_install mercurial
Entonces la interfaz administrativa muestra un men adicional llamado mercurial. Este crea automticamente un repositorio Mercurial local para la aplicacin. Al presionar el botn commit se asigna a la aplicacin actual. Este elemento es experimental y ser mejorado en el futuro.

Mas en appadmin
appadmin no est destinada a ser expuesta al pblico. Est diseada para ayudar a proporcionar un acceso fcil a la base de datos. Se compone de solo dos archivos: un controlador appadmin.py y una vista appadmin.html que son utilizados por todas las acciones en el controlador. El controlador appadmin es relativamente pequeo y fcil de leer, ofreciendo un ejemplo en el diseo de una interfaz de base de datos. appadmin muestra cuales bases de datos estn disponibles y las tablas que existen en cada base de datos. Se pueden insertar registros y la lista de todos los registros de cada tabla por separado. appadmin pagina la salida de 100 registros a la vez. Una vez que un conjunto de registros est seleccionado, el encabezado de las pginas de los cambios, lo que le permite actualizar o eliminar los registros seleccionados. Para actualizar los registros, se introduce una asignacin SQL en el campo de cadena del Query:

title = 'test'

donde los valores de cadena debe ir entre comillas simples. Campos mltiples pueden ser separados por comas. Para borrar un registro, haga clic en la casilla correspondiente para confirmar que est seguro. appadmin tambin puede realizar enlaces si el SQL FILTER contiene una condicin SQL que involucra a dos o ms tablas. Por ejemplo, probemos:

db.image.id == db.comment.image_id

Web2py pasa esto a lo largo del DAL, y entiende que el query est enlazando dos tablas, por lo tanto ambas tablas se seleccionan con un INNER JOINT. He aqu la salida:

Si hace clic en el nmero de un campo id, se obtiene una pgina de edicin del registro con el id correspondiente. Si hace clic en el nmero de un campo de referencia, se obtiene una pgina de edicin del registro referenciado. No se pueden actualizar o eliminar registros seleccionado por un enlace, porque implican registros de varias tablas y esto sera ambiguo.

También podría gustarte