Charla de introducción a zope3: Qué es Zope 3 - Propositos de la plataforma, Aplicación, Qué es Grok, como desarrollar una aplicación con Grok, vistas, zcmls, expresiones tal, generando html desde python, formularios, almacenamiento de datos, contenedores,
2. 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
4. 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
5. 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
6. ¿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
13. 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
14. 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
18. 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
19. El Template
En 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
20. 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=quot;.quot; xmlns=quot;http://namespaces.zope.org/grokquot; />
menttes
25. 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=quot;expresionquot;>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
26. Expresiones TAL
●
path, describen una caminata desde un objeto hacia otro.
“view/current_time”
●
string, permiten combinar fácilmente expresiones path y texto
quot;string:La fecha es ${view/current_time}.quot;
●
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
28. 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
30. 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
31. Recursos estáticos para nuestras páginas
Para usarlo, lo referimos desde index.pt:
<html>
<head>
<link rel=quot;stylesheetquot; type=quot;text/cssquot;
tal:attributes=quot;href static/style.cssquot; />
</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
32. Recursos estáticos para nuestras páginas
El código fuente se verá asi:
<html>
<link rel=quot;stylesheetquot; type=quot;text/cssquot;
href=quot;http://localhost:8080/test/@@/sample/style.cssquot; />
<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
37. Generando HTML desde Python
A 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 quot;<b>YO GROK BOLD</b>quot;
menttes
38. Generando HTML desde Python
Y cambiamos index.pt de la siguiente manera:
<html>
<body>
<p tal:content=quot;structure python:view.some_html()quot;></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
39. 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 quot;YO GROK SIN TEMPLATEquot;
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
41. Haciendo cálculos antes de ver una página
Podemos 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
42. Haciendo cálculos antes de ver una página
Necesitaremos un template index.pt que use alpha:
<html>
<body>
<p tal:content=quot;python:view.alphaquot;>resultado</p>
</body>
</html>
menttes
52. La vista para un modelo
La 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 quot;Esta es informacion del modeloquot;
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
53. La vista para un modelo
Si quisieramos ver esta informacion en nuestro template index.pt:
<html>
<body>
<p tal:content=quot;python:context.information()quot;>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
54. 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 quot;Esta es información del modeloquot;
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
58. Template de edición
Creamos un template edit.pt con el siguiente contenido:
<html>
<body>
<form tal:attributes=quot;action view/urlquot; method=quot;POSTquot;>
Texto a guardar: <input type=quot;textquot; name=quot;textquot; value=quot;quot; /><br />
<input type=quot;submitquot; value=quot;Storequot; />
</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
59. 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
60. 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
61. 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
62. 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
64. 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
65. Reglas de persistencia
Modificamos index.pt para que muestre la lista:
<html>
<body>
Se guardaron los textos:
<ul>
<li tal:repeat=quot;text python:context.listquot; tal:content=quot;textquot;></li>
</ul>
<a tal:attributes=quot;href python:view.url('edit')quot;>
Agregar un texto</a>
</body>
</html>
menttes
66. 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
67. 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
71. 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
72. 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
73. Contenedores
Este es el template asociado con SampleIndex, sampleindex.pt:
<html>
<head>
</head>
<body>
<h2>Entradas existentes</h2>
<ul>
<li tal:repeat=quot;key python:context.keys()quot;>
<a tal:attributes=quot;href python:view.url(key)quot;
tal:content=quot;python:keyquot;></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
74. Contenedores
<h2>Agregar nueva entrada</h2>
<form tal:attributes=quot;action python:view.url()quot; method=quot;POSTquot;>
Nombre: <input type=quot;textquot; name=quot;namequot; value=quot;quot; /><br />
Texto: <input type=quot;textquot; name=quot;textquot; value=quot;quot; /><br />
<input type=quot;submitquot; value=quot;Agregar entradaquot; />
</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