Views, viewlets and content providers

Posted by Graham Stratton Thu, 11 May 2006 10:58:00 GMT

I’ve always had the feeling that understanding the fundamentals of Zope3 won’t take too much longer. Hopefully I’m now one step nearer. In this article I hope to explain how views, viewlets and content providers fit together.

Views have been around in Zope3 since the beginning, whereas viewlets and content providers appeared with formlib in 3.2.

Let’s deal with content providers first. The contentprovider module is very simple. It merely defines an interface for a content provider, which requires an object providing it to have an update() and a render() method. The update() method will be called first so that object can be modified in light of the request (eg form data). Then the render() method is called which should return the final HTML.

The second thing that the contentprovider module does is to enable the ‘provider’ attribute in TAL, which facilitates the use of content providers in templates. Note, though, that when many content providers exist in the same template, the two-stage rendering process is not honoured across providers. Viz., the update() and render() methods will be called on the first provider, then on the second, and so on, instead of all the update() calls preceding all the render() calls.

So, how about a minimal code example? Well, here we go… create a new package called boring, and install a slug in etc/package-includes to load it. Now create a _init_.py like this:

from zope.interface import implements, Interface
from zope.component import adapts, provideAdapter
from persistent import Persistent
from zope.contentprovider.interfaces import IContentProvider
from zope.publisher.interfaces.browser import IDefaultBrowserLayer

class MyContentProvider:
    implements(IContentProvider)
    adapts(Interface, IDefaultBrowserLayer, Interface)

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

    def update(self):
        pass

    def render(self):
        return u'<h1>Look Ma, I rendered something!</h1>'

provideAdapter(MyContentProvider, name="boring.MyContentProvider")

class IBoring(Interface):
    """Interface for a really boring content object""" 

class Boring(Persistent):
    implements(IBoring)

Create a page template called contentprovider.pt like this:

<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:tal="http://xml.zope.org/namespaces/tal" 
      xmlns:metal="http://xml.zope.org/namespaces/metal" 
      metal:use-macro="context/@@standard_macros/page">

<head>
  <title metal:fill-slot="title">Test page</title>
</head>
<body>
<metal:slot fill-slot="body">
  <tal:block replace="structure provider:boring.MyContentProvider" />
</metal:slot>
</html>

And finally create the configure.zcml file to tie it all together like this:

<configure
    xmlns="http://namespaces.zope.org/zope" 
    xmlns:browser="http://namespaces.zope.org/browser" 
    i18n_domain="zope" 
    >

  <class class=".Boring">

    <factory
        id="boring.Boring" 
        description="Boring factory" 
        />

  </class>

  <browser:page
      for=".IBoring" 
      template="contentprovider.pt" 
      name="contentprovider.html" 
      permission="zope.View" 
      />

  <browser:addMenuItem
      class=".Boring" 
      title="Boring object" 
      permission="zope.View" 
      />

</configure>

Then start zope, log in to the ZMI, create a Boring object called boring, and go to /boring/@@contentprovider.html, and should should see the page provided by our content provider. That’s about as simple as it gets.

So what can we do with our content provider now we have one? Well, one thing we can do is to use a viewlet manager as a content provider, so in my next article I’m going to show how to set up viewlets and register them with a viewlet manager.

Posted in  | no comments

Comments

(leave url/email »)

   Comment Markup Help Preview comment