Post on 23-Jan-2015
description
corporate training menttes
Pablo Ambrosio pandres@menttes.com
Desarrollando aplicaciones web con Zope 3
menttes
Que es Zope 3?Zope 3 es un framework de aplicaciones web open source escrito en el lenguaje Python, especialmente apto para desarrollar aplicaciones de manejo de contenido (content management system), intranets, portales.
Provee un arquitectura de componentes y una base de datos transaccional orientada a objetos.
El diseño de Zope 3 esta influenciado por practicas de desarrollo como programación ágil y testeo automatizado.
menttes
Quienes y cuando...
Inicialmente la tecnología Zope fue diseñada por la Zope Corporation.
El desarrollo de Zope 3 comenzo a fines del 2001, y fue lanzado en Noviembre del 2004. Basandose en la experiencia de Zope 2 fue totalmente reescrito, solo conservando su base de datos ZODB.
Es desarrollado por una comunidad libre donde la practica de Sprints es comun.
En el 2006 se crea la Zope foundation para promover la plataforma y proveer soporte a la comunidad.
menttes
Propósitos de la plataforma
● Proveer un entorno de desarrollo atractivo para desarrolladores Python y otros desarrolaldores
● Facilitar la creación de objetos utilizables en Zope:● Posibilitando el uso de clases Python preexistentes● Usando las prestaciones del framework en forma incremental y gradual
● Facilitar la curva de aprendizaje
menttes
Propósitos de la plataforma
● Facilitar el reuso del software● Usando objetos externos a Zope● Agregando, quitando o reemplazando funcionalidades de los objetos existentes.● Proveyendo métodos alternativos de acceso a los objetos (FTP, XMLRPC)
● Aplicando las lecciones aprendidas usando y construyendo Zope 2
● Proveyendo soporte para internacionalización y localización
● Integrando patrones de diseño en Zope
menttes
¿Esta Zope 3 listo para entornos de producción?
Zope 3 se usa en varios sitios de produccion de tamaño considerable. Algunas aplicaciones públicas incluyen:
● Launchpad
● SchoolTool
menttes
menttes
menttes
menttes
Grok
Grok es Zope 3 simplificado.
Fue creado para acortar el tiempo que toma volverse productivo en Zope 3 y disminuye las lineas de código a escribir reemplazando los temidos archivos ZCML.
Es un framework (si, otro).
menttes
¿Que necesitamos saber?
Nos alcanza con conocer el lenguage de programación Python y un entendimento básico de programación web (HTML, forms, URLs).
Para ver como Grok nos puede ayudar a construir nuestra aplicación web, comenzaremos con las cosas simples, para luego ir a hacia usos mas complejos.
menttes
Instalando GrokNecesitaremos:
● Conexión a internet, ya que Grok se instala a traves de la red.● Python 2.4 instalado.
Como grok utiliza código fuente de Zope 3 para su distribución:
● Python "dev" package.● Compilador C (tipicamente gcc) instalado.● easy_install, para poder trabajar con “eggs”.
Listo?
$ sudo easy_install grokproject
menttes
Creando un proyecto
Un proyecto en Grok es un entorno de desarrollo completo.
$ grokproject Sample
Esto creara un nuevo subdirectorio llamado “Sample”, e instalará el proyecto allí. grokproyect automáticamente baja e instala Zope 3 y Grok dentro del directorio.
Luego de proveer el nombre del módulo, al que llamaremos “app.py” (provisto por defecto) y un nombre de usuario y password inicial, estamos listos para comenzar.
menttes
La instancia Zope
$ cd Sample
Desde alli podemos levantar nuestra instancia Zope:
$ parts/instance/bin/zopectl fg
Zope 3 estara disponible en el puerto 8080, nos logeamos ingresando el usuario y contraseña ya indicados:
http://localhost:8080
menttes
menttes
http://localhost:8080/test
menttes
La aplicación
Las fuentes de nuestra aplicacion se encuentran en /src/sample :
..app.pyapp_templatesconfigure.zcml__init__.pyREADME.txtstatic
Grok sabe como asociar el directorio con el módulo según el nombre.
Veamos el código de nuestra aplicación, app.py.
menttes
La aplicación
import grok
class Sample(grok.Application, grok.Container): pass
class Index(grok.View): pass # see app_templates/index.pt
Suficiente para mostrar la página de bienvenida.
menttes
El TemplateEn el directorio app_templates vamos a encontrar el template index.pt:
<html><head></head><body> <h1>Congratulations!</h1>
<p>Your Grok application is up and running. Edit <code>sample/app_templates/index.pt</code> to change this page.</p></body>
Esta es nuestra página de bienvenida.
http://localhost:8080/test
menttes
ZCML (Zope Configuration Markup Language)Pondremos en el directorio de la aplicacion el archivo de configuración configure.zcml. A diferencia de otras aplicaciones Zope 3, este solo contiene una línea que cumple la función de registrar la aplicación.
Podemos ignorar este archivo durante el desarrollo, grok se encarga de hacer la configuración por nosotros
<grok package="." xmlns="http://namespaces.zope.org/grok" />
menttes
Agregando views (vistas)Nuestro view se llama index. Esto significa que es la vista por defecto. Tambien puede ser accedida explicitamente:
http://localhost:8080/test/index
Creamos un segundo template llamado bye.pt en app_templates con el siguiente contenido:
<html><body>
<p>Chau mundo...</p></body></html>
menttes
Agregando views
Para decirle a Grok que use este template modificaremos app.py:
import grok
class Sample(grok.Application, grok.Container): pass
class Index(grok.View): pass
class Bye(grok.View): pass
menttes
Agregando views
Una vista (view) es una forma de ver un modelo, en este caso nuestra aplicación Sample.
La definicion de clase vacía es suficiente para que Grok busque en app_templates por bye.pt.
La regla es que un template debe tener el mismo nombre que su clase asociada, con minúsculas:
http://localhost:8080/test/bye
Los URL en Zope son case sensitive.
En este punto habrá que reiniciar Zope.
menttes
Expresiones TAL
Los Zope Page Templates son documentos XHTML, lo que significa que pueden ser vistos y editados usando herramientas compatibles con XHTML.
ZPT (Zope Page Templates) esta basado en los lenguajes TAL (Template Attribute Language) y METAL (Macro Expansion Template Attribute Language), ambos son específicos de Zope.
Existen varias implementaciones en Python y en otros lenguajes. Puede ser usado con otras aplicaciones.
menttes
Template Attribute Language (TAL)
El Template Attribute Language (TAL) es un lenguaje expresado como atributos en las etiquetas (tags) HTML.
Las etiquetas tienen la forma:
<p tal:comando="expresion">Texto</p>
Todas las declaraciones en TAL consisten de atributos en etiquetas cuyos nombres comienzan con “tal:” , y todas tienen valores asociados, que siempre van entre comillas.
Estas etiquetas son código HTML válido, o sea que estos documentos se pueden editar con cualquier editor de HTML.
menttes
Expresiones TAL● path, describen una caminata desde un objeto hacia otro.
“view/current_time”
● string, permiten combinar fácilmente expresiones path y texto
"string:La fecha es ${view/current_time}."
● python, puede contener cualquier cosa que el lenguaje Python considere una expresión. No se pueden usar declaraciones como if o while.
“python:year != 2005”
● otras... (Exists, Not)
menttes
Comandos TAL
● define
● condition
● repeat
● content
● replace
● attributes
menttes
Propiedades de los Page Templates
El mecanismo de XML y HTML de Zope:
● conserva el template como código XML bien formado
● intenta ser no invasivo usando atributos registrados como namespaces (TAL)
● provee soporte para macros (METAL)
● provee soporte de para internacionalización
menttes
Haciendo páginas dinámicasUsaremos directivas de Zope Page Templates (ZPT) para generar contenidos dinámicos. Cambiando index.pt:
<html><body>
<p tal:content="python: 1 + 1">esto se reemplaza</p></body></html>
El código fuente se verá así:
<html><body>
<p>2</p></body></html>
menttes
Recursos estáticos para nuestras páginas
Usualmente necesitaremos referirnos a recursos en nuestras páginas, como imágenes, archivos CSS y código Javascript. Como ejemplo agregemos un poco de estilo en nuestra página
Creamos un directorio nuevo llamado “static” en el “sample package” (src/sample/static). Dentro creamos un archivo llamado style.css:
body { backgroundcolor: #FF0000;}
menttes
Recursos estáticos para nuestras páginasPara usarlo, lo referimos desde index.pt:
<html><head>
<link rel="stylesheet" type="text/css" tal:attributes="href static/style.css" />
</head><body>
<p>Hola mundo!</p></body></html>
Notar el uso de la directiva tal:attributes. Usamos Zope Page Templates para generar dinámicamente el enlace al archivo style.css.
menttes
Recursos estáticos para nuestras páginas
El código fuente se verá asi:
<html><link rel="stylesheet" type="text/css"
href="http://localhost:8080/test/@@/sample/style.css" /><body>
<p>Hola mundo!</p></body></html>
Igualmente poniendo los archivos de imágenes o los .js en el directorio “static” y creando el URL a ellos usando static/<archivo> en el page template.
menttes
Usando métodos view
ZPT esta deliberadamente limitado en cuanto a lo que permite hacer con Python. Es una buena práctica de diseño hacer cualquier cosa que sea un poco mas complicada con código Python.
Usar código Python arbitrariamente desde ZPT es fácil, agregamos métodos a la clase view y los usamos desde el template.
Si quisieramos mostrar la fecha actual...
>>> from datetime import datetime
esta declaración esta fuera de las capacidades de los ZPT, no esta permitido importar módulos dentro de un template.
menttes
Usando métodos view
Integremos un poco de código en nuestro proyecto Grok. Modificando app.py:
import grokfrom datetime import datetime
class Sample(grok.Application, grok.Container): pass
class Index(grok.View): def current_datetime(self): now = datetime.now() return now.strftime('%Y%m%d %H:%M')
menttes
Usando métodos view
Hemos agregado un método que devuelve un string. Ahora mostremos este string en la página index.pt:
<html><body>
<p tal:content="python:view.current_datetime()">Hola</p></body></html>
veremos algo como:
20070227 17:21
menttes
Usando métodos view
Una forma un poco mas corta y mas sencilla de leer a veces en ZPT es usando una expresion path:
<html><body>
<p tal:content="view/current_datetime"></p></body></html>
Corriendo esto se obtiene el mismo resultado que en el caso anterior.
menttes
Generando HTML desde PythonA veces se obtendra o generara HTML desde código Python para luego incluirlo en una página. Por razones de seguridad contra crossscripting TAL automaticamente escapa HTML > y <. Con la directiva “structure” se le puede decir explícitamente a TAL que no escape HTML, asi se puede pasara literalmente al template:
import grok
class Sample(grok.Application, grok.Container): pass
class Index(grok.View): def some_html(self): return "<b>YO GROK BOLD</b>"
menttes
Generando HTML desde Python
Y cambiamos index.pt de la siguiente manera:
<html><body>
<p tal:content="structure python:view.some_html()"></p></body></html>
veremos el texo:
YO GROK BOLD
el HTML generado fue integrado en la página. Sin la directiva “structure” se vería algo como:
<b>YO GROK BOLD</b>
menttes
Views completamente dirijidas con Python
A veces es inconveniente usar templates. Tal vez ni siquiera estamos devolviendo una página HTML. En estos casos se peude usar el método render en la view:
import grok
class Sample(grok.Application, grok.Container): pass
class Index(grok.View): def render(self): return "YO GROK SIN TEMPLATE"
En este caso queda el template index.pt dando vueltas, ante la ambiguedad Grok se niega a adivinar, luego habra que remover el template.
menttes
Configurando el content-typeCuando se genera el contenido desde el view puede ser útil cambiarlo a otra cosa que no sea text/plain:
import grok
class Sample(grok.Application, grok.Container): pass
class Index(grok.View): def render(self): self.response.setHeader('ContentType',
'text/xml; charset=UTF8') return "<doc>Un poco de XML</doc>"
Todas las vistas en Grok tienen la propiedad “response” que se puede usar para manipular los headers de respuesta.
menttes
Haciendo cálculos antes de ver una páginaPodemos hacer que el view haga ciertos cálculos para nuestra página y asi hacer el cálculo una vez por recarga (aunque usemos el valor múltiples veces en la página).
Esto se puede hacer usando el método update en la clase de la vista:
import grok
class Sample(grok.Application, grok.Container): pass
class Index(grok.View): def update(self): self.alpha = 2 ** 8
Esto setea “alpha” en la vista justo antes de que se muestre el template.
menttes
Haciendo cálculos antes de ver una página
Necesitaremos un template index.pt que use alpha:
<html><body>
<p tal:content="python:view.alpha">resultado</p></body></html>
menttes
Leyendo parámetros URL
Usualmente cuando desarrollemos nuestra aplicación vamos a querer no solo mostrar datos, sino tambien recibirlos (y procesarlos). Una forma simple de hacer esto es obteniendo la informacion como parámetros en un URL.
Hagamos una aplìcacion que resuelva sumas. Si le pasamos el siguiente URL a la aplicación:
http://localhost:8080/test?value1=3&value2=5
deberíamos obtener su suma (8) como resultado en la página.
menttes
Leyendo parámetros URL
Modificamos app.py para que se vea asi:
import grok
class Sample(grok.Application, grok.Container): pass
class Index(grok.View): def update(self, value1, value2): self.sum = int(value1) + int(value2)
menttes
Leyendo parámetros URL
Necesitaremos un index.pt que use sum:
<html><body>
<p tal:content="python:view.sum">suma</p></body></html>
Otras sumas funcionaran por supuesto:
http://localhost:8080/test?value1=50&value2=50
menttes
Leyendo parámetros URL
Sino pasamos parámetros por el URL (value1 y value2) obtendremos un error:
A system error occurred.
En el traceback donde corremos el Zope veremos:
TypeError: Missing argument to update(): value1
Este es el mensaje de error relevante.
menttes
Leyendo parámetros URL
Modificamos el codigo para que funcione aunque no preoveamos parámetros:
import grok
class Sample(grok.Application, grok.Container): pass
class Index(grok.View): def update(self, value1=0, value2=0): self.sum = int(value1) + int(value2)
menttes
Formularios simplesUsemos un formulario para pasar los parámetros. Cambiamos index.pt para que contenga un formulario como:
<html><body>
<form tal:attributes="action python:view.url()" method="GET"> Valor 1: <input type="text" name="value1" value="" /><br /> Valor 2: <input type="text" name="value2" value="" /><br /> <input type="submit" value="Sumar!" />
</form><p>La suma es: <span tal:replace="python:view.sum">suma</span></p>
</body></html>
menttes
Formularios simples
<form tal:attributes="action python:view.url()" method="GET">
Un detalle para notar en este código es que generamos la acción del formularion dinámicamente. Básicamente le decimos al formulario que se reenvíe a si mismo. El método url, propio de Grok, nos permite obtener el URL de la misma vista (y otros URLs tambien).
Todavía tenemos algunos problemas con ese código. Si no cargamos parámetros y enviamos el formulario obtendremos un error como el siguiente:
File "../app.py", line 8, in update self.sum = int(value1) + int(value2)ValueError: invalid literal for int():
menttes
Formularios simples
Si los parámetros son string vacíos no podrán ser convertidos a enteros. Otra cosa poco simpática es que mostramos una suma (0) aun cuando no proveeemos datos:
class Index(grok.View): def update(self, value1=None, value2=None): try: value1 = int(value1) value2 = int(value2) except (TypeError, ValueError): self.sum = "No hay suma" return self.sum = value1 + value2
En Grok uno puede usar las bibliotecas schema y formlib de Zope 3 para automatizar la generacion de formularios.
menttes
Modelos
Hemos visto como mostrar páginas web, ahora veremos un poco mas sobre lo que estamos mostrando: el modelo. El modelo contiene la lógica de la aplicación, independientemente de la vista.
La vista, junto con el template, es responsable de mostrar la información y su interfaz de usuario. El modelo representa la información (o contenido) de los que trata la aplicación , como documentos, entradas de blog o páginas wiki. El modelo no debe saber nada sobre como son mostrados los datos.
En una aplicacion Grok, los modelos se definen como subclases de grok.Model o grok.Container.
menttes
La vista para un modeloLa clase Sample es un grok.Container, asi que la usaremos para ver los principios básicos de modelos. Modifiquemos app.py para que tenga información disponible:
import grok
class Sample(grok.Application, grok.Container): def information(self): return "Esta es informacion del modelo"
class Index(grok.View): pass
En este caso, la información esta hardcodeada, pero podemos imaginar que la estamos extrayendo de algun otro lado, como una base de datos o el file system.
menttes
La vista para un modelo
Si quisieramos ver esta informacion en nuestro template index.pt:
<html><body>
<p tal:content="python:context.information()">reemplazado</p></body></html>
Vimos que se pueden acceder métodos y atributos de una vista usando la palabra clave view en un template.
De la misma manera la palabra context esta disponible en cada template, y nos permite acceder informacion en el objeto contextual que la vista esta mostrando. En este caso una instancia de Sample.
menttes
La vista para un modelo
Hagamos que la vista modifique la forma en que vemos la información (sin modificar los datos del modelo claro). Cambiemos app.py:
import grok
class Sample(grok.Application, grok.Container): def information(self):
return "Esta es información del modelo"
class Index(grok.View): def reversed_information(self): return ''.join(reversed(self.context.information()))
El objeto context tambien puede ser accedido desde la clase de la vista.
menttes
Almacenando datos
¿Que tal si quisieramos almacenar alguna información? Como algun dato ingresado por el usuario. La forma mas sencilla de hacer esto con Zope es usando la Zope Object DataBase (ZODB).
La ZODB es una base de datos de objetos Python. Se puede almacenar cualquier objeto Python en ella siempre que se sigan algunas simples reglas (las “Reglas de Persistencia”). Nuestro objeto de aplicacion Sample está almacenado en la base de datos, luego podemos almacenar información en él.
menttes
Almacenando datos
Creemos una aplicación que almacene un tramo de texto. Usaremos una vista para visualizar el texto (index) y otra para editarlo (edit). Esta es app.py:
import grok
class Sample(grok.Application, grok.Container): text = 'texto por defecto'
class Index(grok.View): pass
class Edit(grok.View): def update(self, text=None): if text is None: return self.context.text = text
menttes
Almacenando datos
Esto setea el atributo text en la instancia del objeto Sample en la base de datos, sobreescribiendo el texto por defecto de la clase. Cambiamos el template index.pt para que se lea:
<html><body>
<p>El texto: <span tal:replace="python:context.text">texto</span></p><p><a tal:attributes="href python:view.url('edit')">Edit this page</a></p>
</body></html>
Dándole al método url un string como argumento generará un URL a la vista llamada como el string en el mismo objeto (test), en este caso test/edit.
menttes
Template de ediciónCreamos un template edit.pt con el siguiente contenido:
<html><body>
<form tal:attributes="action view/url" method="POST">Texto a guardar: <input type="text" name="text" value="" /><br /><input type="submit" value="Store" />
</form></body></html>
La página se reenvía a si misma y se verá el texto ingresado. Esto significa que el texto esta almacenado en la base de datos.
http://localhost:8080/test
Se puede reiniciar Zope y volver a la página index y se verá que los cambios persisten.
menttes
Redireccion
Cambiemos el formulario de edit para que redirija devuelta a la página de index luego de presionado el boton submit:
class Edit(grok.View): def update(self, text=None): if text is None: return self.context.text = text self.redirect(self.url('index'))
La última línea es la nueva. Usamos el método url en la vista para construir el URL de la página index. Dado que estamos en un template, podemos llamar el método sobre self. Luego se lo pasamos a otro método disponible en todas las subclases de grok.View, redirect.
menttes
Reglas de persistencia
● Para almacenar datos de una clase en la ZODB debemos hacerla subclase de persistent.Persistent. La forma mas sencilla de hacer esto con Grok es hacerla subclase de grok.Model o grok.Container.
menttes
Reglas de persistencia
● Para almacenar instancias éstas deben estar conectadas a otras clases persistentes que ya esten almacenadas. La forma mas simple con Grok es agregarlas de alguna forma al objeto grok.Application, directa o indirectamente. Esto se hace seteandolas como un atributo o poniéndolas en un contenedor (si hacemos la aplicacion subclase de grok.Container).
menttes
Reglas de persistencia
● Para asegurarse que la ZODB se entere que se ha cambiado un objeto mutable (como una lista o diccionario Python) en una instancia, se setea el atributo _p_changed en esa instancia a True. Esto solo es necesario cuando el atributo no es persistente por si mismo. Tampoco es necesario cuando se crea o sobreescribe un atributo directamente usando =.
menttes
Reglas de persistencia
Si se construye el contenido de la aplicación con subclases de grok.Model y grok.Container prácticamente se siguen todas las reglas.
Si usamos un objeto mutable como una lista o un diccionario para almacenar datos necesitamos tomar una acción especial. Modificando el código anterior para usar una lista:
class Sample(grok.Application, grok.Container): def __init__(self): super(Sample, self).__init__() self.list = []
menttes
Reglas de persistencia
def addText(self, text): self.list.append(text)
self._p_changed = True
class Edit(grok.View): def update(self, text=None): if text is None: return self.context.addText(text) self.redirect(self.url('index'))
Creamos un método addText en el modelo que se encarga de actualizar la lista e informar a la ZODB de esto. Asi cualquier código de vista puede usar la API de Sample sin preocuparse por las reglas de persistencia, ya que es una responsabilidad del modelo.
menttes
Reglas de persistencia
Modificamos index.pt para que muestre la lista:
<html><body>
Se guardaron los textos:<ul> <li tal:repeat="text python:context.list" tal:content="text"></li></ul>
<a tal:attributes="href python:view.url('edit')">Agregar un texto</a>
</body></html>
menttes
Asociando explícitamente una vista a un modelo
Como sabe Grok que una vista pertenece a un determinado modelo? En los ejemplos vistos Grok hace esta asociacion automáticamente. Esto se pudo hacer porque solo hay un modelo definido en el módulo (Sample). Detras de escena Grok hizo al modelo ser el context de todas las vistas.
Todo lo que Grok hace implícitamente también se puede hacer explícitamente. Esto es útil cuando se necesite decirle a Grok que hacer, sobreescribiendo el comportamienteo por defecto. Para asociar una vista con un modelo se usa la anotacion de clase grok.context.
Una anotacion de clase es una forma declarativa de decirle a Grok algo acerca de una clase Python.
menttes
Asociando explícitamente una vista a un modelo
Sea la siguiente app.py:
import grok
class Sample(grok.Application, grok.Container): pass
class Index(grok.View): grok.context(Sample)
class Bye(grok.View): grok.context(Sample)
Lo único hecho es poner explícita la relación entre el modelo y la vista, usando la directiva grok.context.
menttes
Contenedores
Un contenedor es un tipo especial de objeto modelo que puede contener otros objetos. La aplicación Sample es un contenedor, al ser subclase de grok.Container.
Una aplicación Grok está típicamete compuesta por contenedores y modelos. Con modelos siendo contenidos en dichos contenedores. A su vez los modelos contenidos tambien pueden ser contenedores, ya que estos son a su vez modelos.
menttes
Contenedores
Desde la perspectiva Python, se puede pensar en contenedores como diccionarios. Permiten acceso por item (container['key']) para obtener sus contenidos. Tambien definen métodos como keys() y values().
Los contenedores ademas proveen otras funcionalidades propias. Son persistentes, y cuando son modificados no es necesario usar el atributo _p_changed. Tambien implementan eventos especiales que pueden ser escuchados cuando nuevos items son agregados en los contenedores o removidos.
menttes
ContenedoresProbemos un objeto de aplicación que tenga una página index donde se muestran sus contenidos. Se puede seleccionar un item del contenido para verlo. Bajo la lista habrá un formulario que premita agregar nuevo contenido. Este será app.py:
import grok
class Sample(grok.Application, grok.Container): pass
class Entry(grok.Model): def __init__(self, text): self.text = text
Hemos creado un objeto que no es de aplicación, Entry. Es sólo un grok.Model. Necesita ser creado con un texto como argumento al cual almacena.
menttes
Contenedores
class SampleIndex(grok.View): grok.context(Sample) grok.name('index')
def update(self, name=None, text=None): if name is None or text is None: return self.context[name] = Entry(text)
Luego siguen las vistas. Habra una para el contenedor Sample. Cuando su update es llamado con dos valores, name y text, creara una nueva instancia de Entry con el texto dado, y la pondra en el contenedor con el nombre name. Se usa la notacion tipo diccionario para agregar la nueva Entry en el contenedor.
menttes
Contenedores
class EntryIndex(grok.View): grok.context(Entry) grok.name('index')
Hay otro detalle, la idea es que estas vistas sean de tipo index. Esto no se puede deducir automáticamente por el nombre de las clases, sin embargo, si lo dejamos solo Grok hubiese llamado a las vistas sampleindex y entryindex.
Para este caso existe otra anotacion de clase que puede ayudar, grok.name. Se puede usar en ambas clases (grok.name('index')) para decirle explícitamente a Grok lo que queremos.
menttes
Contenedores
Este es el template asociado con SampleIndex, sampleindex.pt:
<html><head></head><body> <h2>Entradas existentes</h2> <ul> <li tal:repeat="key python:context.keys()"> <a tal:attributes="href python:view.url(key)" tal:content="python:key"></a> </li> </ul>
Usamos keys() para obtener la lista de todos los nombres de los items en el contenedor. Creamos un link a los items usando view.url().
menttes
Contenedores
<h2>Agregar nueva entrada</h2> <form tal:attributes="action python:view.url()" method="POST"> Nombre: <input type="text" name="name" value="" /><br /> Texto: <input type="text" name="text" value="" /><br /> <input type="submit" value="Agregar entrada" /> </form>
</body>
En esta sección se muesta un formulario que envía los datos a la propia página index. Tiene dos campos, name y text, que son manejados por update().
menttes
ContenedoresFinalmente, una página index para Entry. Tiene un template para mostrar el atributo text:
<html><head></head><body> <h2>Entrada <span tal:replace="python:context.__name__">
</span> </h2>
<p tal:content="python:context.text"></p></body>
</html>
Reiniciamos Zope y probamos la aplicación.
menttes
menttes
Referencias
● www.zope.org
● www.archive.org/details/grok_todo_part1
● grokzope.org
● worldcookery.com
● wiki.zope.org/zope3
● www.zope.org/Documentation/Books/ZopeBook/2_6Edition/ZPT.stx
● www.zope.com
● www.schooltool.org
● launchpad.net paleosoft.org foundation.zope.org