Creating a minimalistic Zope 3 View

Learn how to create a simple Page Template driven browser view using Zope 3 techniques.

Purpose

Creating Python Scripts and Page Templates in skin layers using the Zope Management Interface (ZMI) is a quick-and-easy approach to customizing Plone. However, some of the drawbacks of this approach are that you can't use standard developer tools such as an IDE or a version control system. In addition, when you edit Python code using your web browser, you are sending untrusted code over the internet. For security reasons, it is necessary to run this Python code in a security sandbox, which means that you are restricted from performing many common operations in Python.

By creating an ordinary Python package you can create your own custom Page Template, which is backed by a plain Python class that does not impose any of the security restrictions of Python Scripts. This approach requires some additional knowledge beyond ZMI customizations, but should be followable by a novice Developer. The traditional Zope 2 methods of making unrestricted Python available were to either create an External Method or create a Zope 2 Product. Using Zope 3 techniques we can create an ordinary Python package containing a simple View component that can be applied to any content item in your Plone site.

Prerequisities

Basic knowledge of Python. Basic knowledge of Zope Page Templates. Basic knowledge of the layout of your Zope 2 and Plone 3 installation.

Creating a simple Package with a simple View

Create a Python package called 'simpleview' inside the lib/python directory of your Zope instance. Inside this 'simpleview' directory create a file called '__init__.py'. The existence of an  '__init__.py' file means that Python will treat that directory as a Python package. When Python imports that package it calls any code in __init__.py, In this case we do not need to run any special code, so we will just write a single line comment to amuse ourselves:

# poof! he said and it was a package

Now we will create a Python class to hold the code for our View component, a Page Template file that will hold the HTML and TAL, and a ZCML file that will tell Zope to associate our Python class and Page Template file with each other.

Let's start with the Python class, we will put this code in a file called 'simple.py'. The BrowserView base class you inherit from assigns the content item that your View is rendered for to self.context, while the incoming HTTP Request object is assigned to self.request. Each method you make available in your class is available to be called from your Page Template:

from Products.Five import BrowserView

class SimpleView(BrowserView):
    
    def content_item_id(self):
        return self.context.getId()
    
    def user_agent(self):
        return self.request.get('HTTP_USER_AGENT','')

Next create a file called 'simple.pt'. You can access your Python class with the name view from within your Page Template.

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      xmlns:tal="http://xml.zope.org/namespaces/tal"
      xmlns:metal="http://xml.zope.org/namespaces/metal"
      xmlns:i18n="http://xml.zope.org/namespaces/i18n"
      lang="en"
      metal:use-macro="here/main_template/macros/master"
      i18n:domain="plone">

<body>

<div metal:fill-slot="main">
	
	<h1 tal:content="view/content_item_id" />
		
	<p>Your browser identifies as <span tal:replace="view/user_agent" /></p>
	
</div>

</body>
</html>

Finally, you need to tell Zope that you have a View component, and that you wish to use your Page Template to render that component. Create a file called 'configure.zcml' and put the following XML in it:

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

  <browser:page
      for="*"
      name="simple-view"
      class=".simple.SimpleView"
      template="simple.pt"
      permission="zope2.View"
      />

</configure>

The browser:page directive has a number of attributes. These are:

  • for: Registers the page for a specific Interface. The special syntax * means that this is a generic View that can be applied to any Interface.
  • name: This is what your View is called in the URL.
  • class: The Python class that backs your Page Template.
  • template: The Page Template file for your View.
  • permission: The permission required to access your View.

Finally, you need to do one last step, and that is to tell Zope to include your new package. You need to create a file, called a ZCML slug, inside your Zope instances etc/package-includes directory called 'basicview-configure.zcml' that has a single line of text:

<include package="simpleview" />

It is recommended that if you are going beyond this simple customization that you learn how to create a buildout driven Zope instance, and use the paster command to make your development packages available as Python eggs. This saves you the hassle of having to remember to manually manage the configuration inside the etc/package-includes directory, as well as providing you with a strong set of tools for managing your Plone instance and your Python eggs.

Finally, you can call your View and see it rendered in your web browser by going to the URL:

http://localhost:8080/myplonesite/@@simple-view

It is not necessary include the @@ syntax, but it avoids conflict in the case of having a content item also called 'simple-view' inside your Plone site. You can remember the @@ syntax by associating it with a pair of eyes, this is intended to represent a View.

Creating a minimalistic Zope 3 View

Posted by srisri at Jun 13, 2008 05:10 AM
Hi.. i have tried out this example, but i am not able to load the page..

i have placed the zcml file here..
Program Files\Plone 3\Zope\skel\etc\package-includes

and the url,
http://localhost:8070/@@simpleview

my plone instance runs at port:8070
   zmi :8080

i am not sure where i am going wrong...
plzzz help me

thanks & regards,
srisri

Add package-includes in correct location

Posted by Farida Rahman at Jun 25, 2008 09:22 PM
Add a package-includes directory to \Program Files\Plone 3\etc directory in your case. Then in the directory add the zcml and you will be see simple-view work.

So, so very close!

Posted by Herman Geldenhuys at Aug 28, 2008 10:05 AM
Thanks Kevin!

At last, somebody with a thorough example of what I'm trying to accomplish, thanks.

I've run into a problem though. Everything is smooth sailing, until I hit this part:
======================================================
Finally, you need to do one last step, and that is to tell Zope to include your new package. You need to create a file, called a ZCML slug, inside your Zope instances etc/package-includes directory called 'basicview-configure.zcml' that has a single line of text:

<include package="simpleview" />
======================================================

Once I include that little zcml slug, my gun backfires. Back inside Zope, when I add a new "Plone Site", I get the following error:
======================================================
('No traversable adapter found', {'extension_profiles': ({'product': 'kupu', 'description': 'Extension profile for Kupu', 'for': , 'title': 'Kupu', 'version': u'1.4.11', 'path': 'plone/profiles/default', 'type': 2, 'id': 'kupu:default'},), 'args': (), 'base_profiles': (), 'default_profile': 'Products.CMFPlone:plone'})
======================================================

When I change the slug to <include package="simpleview" file="configure.zcml"/>, still I get this error. Only when I remove this file completely, does my Zope instance act normally.

I used Plone 3.1.5 and I created the simpleview package in my ${PloneInstance}/Products folder (even tried lib/python in both Zope and Plone folders).


Do you have any ideas of what I'm doing wrong here?

Thanks,
Herman (aka, desperate Plone2 developer)

Faced problem due to typo in slug file name

Posted by Chetan Thapliyal at Oct 23, 2008 08:51 AM
Hi,

I am a newbie in Plone. I followed the instructions in article with my own package. In the end all I get was "Page doesn't exist" message. On analyzing I noticed that I named ZCML slug as `basicview_configure.zcml` instead of `basicview-configure.zcml`. I corrected this and page appeared. Can anyone please explain if it is a convention to use this exact name ?

package-includes behaviour

Posted by Kevin Teague at Oct 23, 2008 05:22 PM
Yes, the slug filename needs to end with '-configure.zcml' as this is the suffix that gets explicitly searched for. All '*-configure.zcml' files are evaluated after all other configuration is done. Files in that directory matching *'-meta.zcml' are evaluated earlier during meta directive processing.