What is the difference between template in ZCML and ViewPageTemplateFile

529 Views Asked by At

When creating a BrowserView in Plone, I know that I may optionally configure a template with ZCML like so:

<configure

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

    <browser:page
        …
        class=".foo.FooView"
        template="foo.pt"
        …
        />

</configure>

Or alternatively in code:

# foo.py
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from zope.publisher.browser import BrowserPage


class FooView(BrowserPage):
    """
    My View
    """

    def __call__(self):
        return ViewPageTemplateFile('foo.pt')(self)

Is there any difference between the two approaches? They both appear to yield the same result.

Sub-question: I know there is a BrowserView class one can import, but conventionally everyone uses BrowserPage. What if any significant differences exist between the two classes?

3

There are 3 best solutions below

3
On BEST ANSWER

Note: To be fully equivalent to ZCML you should set the index variable to specify which template you are using. That way the TTW customization will work too.

# foo.py
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from zope.publisher.browser import BrowserPage
class FooView(BrowserPage):
    index = ViewPageTemplateFile('foo.pt')

One other pattern you can use with a browser view is adding an update method.

class FooView(BrowserPage):
    index = ViewPageTemplateFile('foo.pt')
    def __call__(self):
        self.update()
        return self.index()

    def update(self):
        self.portal_catalog = ...  # initialize code

But this is not the question.


So what is the difference? There is no difference. A browser view must be a callable. The ZCML directive builds this callable in a way the object has an index which must return the rendered page.

But creating the template on each call (your example) there is one difference: you are creating a new instance of the template on each call of the browser view. This is not the case with class variable.

One last option: You don't need a class argument in the directive

<configure xmlns:browser="http://namespaces.zope.org/browser">
  <browser:page
    …
    template="foo.pt"
    …
    />
</configure>

For more information, you should read the code of the directive, which uses SimpleViewClass where src is the template name.

0
On

AFAIK, there is no difference. The ZCML directive generates a ViewClass with a ViewPageTemplateFile and renders the template on a __call__. See zope.browserpage.metaconfigure.page lines 132, 151.

That is exactly the same you do in your example: you explicitly instantiate the template in your __call__ method.

As to the subquestion: From my understanding, the significant differences are not apparent in the context of Zope2/Plone. Based on the interface (zope.publisher.interfaces.browser.IBrowserPage), the BrowserPage is the base class you want to inherit from, since it implements __call__ and browserDefault. Yet, it does not seem to matter if you use BrowserPage or BrowserView with Plone.

1
On

In Plone, you can customize the template TTW (via portal_view_customizations) only when the template is registered explicitly (e.g. using ZCML or Grok-directives).

If you define template only in your __call__, you won't see it in portal_view_customizations.

Also, I'd guess that loading template within a method would reload it from the disk for every view instance (every request).