17. Vistas - Parte II: Una vista por defecto para la “charla”

Vista de clases

Anteriormente hemos escrito una vista de demostración que también utilizamos para experimentar con las plantillas de página. Vamos a echar un vistazo a la ZCML y la Page Template de nuevo. Yo he ampliado el código sólo un poco.

El archivo browser/configure.zcml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<configure xmlns="http://namespaces.zope.org/zope"
    xmlns:browser="http://namespaces.zope.org/browser"
    i18n_domain="ploneconf.site">

    <browser:page
       name="demoview"
       for="*"
       layer="zope.interface.Interface"
       class=".views.DemoView"
       template="templates/demoview.pt"
       permission="zope2.View"
       />

</configure>

El archivo browser/views.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from Products.Five.browser import BrowserView

class DemoView(BrowserView):
    """ This does nothing so far
    """

    def __init__(self, context, request):
        self.context = context
        self.request = request

    def __call__(self):
        # Implement your own actions

        # This renders the template that was registered in zcml like this:
        #   template="templates/demoview.pt"
        return super(DemoView, self).__call__()
        # If you don't register a template in zcml the Superclass of
        # DemoView will have no __call__-method!
        # In that case you have to call the template like this:
        # from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
        # class DemoView(BrowserView):
        # template = ViewPageTemplateFile('templates/demoview.pt')
        # def __call__(self):
        #    return self.template()

¿Recuerdas el término MultiAdapter? La browser page es sólo un MultiAdapter. La declaración ZCML browser:page registra un MultiAdapter y agrega cosas adicionales que se necesitan para una browser view.

Un adaptador adapta cosas, un MultiAdapter adapta múltiple cosas.

Al introducir una dirección URL, Zope trata de encontrar un objeto para él. Al final, cuando Zope no encuentra ningún objeto más, pero todavía hay un elemento de ruta, o no hay más elementos de rutas, Zope busca un adaptador que va a responder a la solicitud.

El adaptador se adapta la solicitud y el objeto que Zope ha encontrado con la dirección URL. La clase de adaptador se crea instanciada con los objetos que han de adaptarse, entonces se llama.

El código fuente anterior hace la misma cosa que la implementación estándar haría. Hace que el contexto y la solicitud estén disponibles como variables en el objeto.

Yo he escrito estos métodos porque es importante entender algunos conceptos importantes.

El método init es llamado mientras Zope es todavía esta tratando de encontrar una vista. En esa fase, la seguridad no se ha resuelto. El código no comprueba la seguridad. Por razones históricas, muchos errores que se producen en el método init puede resultar en una página no encuentre el error en lugar de una excepción.

No hagas mucho a todos en el método init. En su lugar usted tiene la garantía que el método call es llamado antes de cualquier otra cosa (excepto el método init). Tiene los controles de seguridad en su lugar y así sucesivamente.

Desde un punto de vista práctico, considere el método call en su método init, la mayor diferencia es que este método debe retornar el HTML listo. Deje a su clase base manejar la generación de HTML.

La vista por defecto

Ahora nosotros finalmente agregamos la vista por defecto para las charlas en views.py

El archivo browser/configure.zcml

<browser:page
   name="talkview"
   for="*"
   layer="zope.interface.Interface"
   class=".views.TalkView"
   template="templates/talkview.pt"
   permission="zope2.View"
   />

El archivo browser/views.py

from plone.dexterity.browser.view import DefaultView

...

class TalkView(DefaultView):
    """ The default view for talks
    """

La clase base DefaultView en el paquete plone.dexterity solamente existe para los Objetos Dextertity y tiene algo de gran utilidad a disposición de la plantilla:

  • view.w es un diccionario de todos los widgets de pantalla, con clave de nombres de campos. Esto incluye widgets de conjunto de campos alternativos.

  • view.widgets contiene una lista de widgets en esquema de ordenar para el conjunto de campos predeterminado.

  • view.groups contiene una lista de conjunto de campos con el fin de ordenar conjunto de campo.

  • view.fieldsets contiene un nombre de conjunto de campo mapeado un diccionario a conjunto de campo

  • En un conjunto de campos (grupo), puede acceder a una lista de widgets para obtener los widgets en ese conjunto de campo

Nota

La vista plone.dexterity.browser.view.DefaultView tiene las mismas características que el equivalente Grok plone.directives.dexterity.DisplayForm.

La plantilla templates/talkview.pt usa el patrón view/w/<fieldname>/render para hacer algunos widgets.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
    lang="en"
    metal:use-macro="context/main_template/macros/master"
    i18n:domain="ploneconf.site">
<body>
    <metal:content-core fill-slot="content-core">
        <p>Suitable for <em tal:replace="structure view/w/audience/render"></em>
        </p>

        <div tal:content="structure view/w/details/render" />

        <div tal:content="context/speaker">
            User
        </div>
    </metal:content-core>
</body>
</html>

Después de un reinicio, podemos probar nuestra vista, yendo a un tipo de contenido talk agregado y agrégale a la dirección URL /talkview.

Debemos decirle a Plone, que la vista talkview debe ser utilizado como la vista predeterminada para las charlas en lugar de la vista incorporada.

Esta es una configuración que puede cambiar en tiempo de ejecución y se almacena en la base de datos, como tal, también es gestionado por perfiles GenericSetup.

Nota

Para cambiarlo a través de la Web valla a la ZMI (http://localhost:8080/Plone/manage), luego vaya a la herramienta portal_types y seleccione el tipo para el cual el nuevo tipo de contenido debe ser seleccionable (talk). Ahora agregue talkview a la lista Available view methods. Ahora la nueva vista está disponible en el menú Mostrar. Para que sea la vista predeterminada ingrese esta vista en la sección Default view method.

Abra el archivo profiles/default/types/talk.xml:

1
2
3
4
5
6
7
...
<property name="default_view">talkview</property>
<property name="view_methods">
    <element value="talkview"/>
    <element value="view"/>
</property>
...

Vamos a tener que reinstalar nuestro complemento o ejecutar el paso GenericSetup llamado typeinfo entonces Plone aprende sobre el cambio.

También podríamos decirle a Plone sobre esto en el ZMI: http://localhost:8080/Plone/portal_types/talk/manage_propertiesForm

Mejoremos la vista talkview para mostrar toda la información que queremos.

El archivo templates/talkview.pt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
      metal:use-macro="context/main_template/macros/master"
      i18n:domain="ploneconf.site">
<body>
    <metal:content-core fill-slot="content-core">

        <p>
            <span tal:content="context/type_of_talk">
                Talk
            </span>
            suitable for
            <span tal:replace="structure view/w/audience/render">
                Audience
            </span>
        </p>

        <div tal:content="structure view/w/details/render">
            Details
        </div>

        <div class="newsImageContainer">
            <img tal:condition="python:getattr(context, 'image', None)"
                 tal:attributes="src string:${context/absolute_url}/@@images/image/thumb" />
        </div>

        <div>
            <a class="email-link" tal:attributes="href string:mailto:${context/email}">
                <strong tal:content="context/speaker">
                    Jane Doe
                </strong>
            </a>
            <div tal:content="structure view/w/speaker_biography/render">
                Biography
            </div>
        </div>

    </metal:content-core>
</body>
</html>

Ejercicio

Agregar el nuevo campo “room” con el tipo de contenido Talk (a través de la Web) y mostrarlo debajo del campo Audience en la browser view, debe contener los siguientes datos:

  • Título: Room

  • Posible valores: Room 101, Room 102, Auditorium

Solución

<p>
    <span tal:replace="structure view/w/room/render">
        Room
    </span>
</p>