I have a quite old product which contains several Archetypes-based types. I'd like to have special views for those types for use with my ajaxnavigation product; the idea is,
an ajax-nav view to return the whole information about the object in JSON format, and
an embed view, using a template, which is used internally to create the content information.
I have a subpackage ajax_nav which is activated if my ajaxnavigation package is installed.
In its configure.zcml, I have entries like this one:
This looks perfectly reasonable to me, but it won't work. I expected the effect to be:
For every context object which implements the interface given in the for attribute,
when called via .../@@embed,
use the EmbedView class of the .video module to provide the view data
which is used for the video-embed.pt template.
That ZCML directive should create the connection to the template, right?
However, the template is not used; instead, I get the raw data from the EmbedView.__call__ result.
My Python modules look like this:
# _base.py
from Products.Five.browser import BrowserView
from plone.uuid.interfaces import IUUID
class BaseEmbedView(BrowserView):
def __call__(self):
context = self.context
res = {
'UUID': IUUID(context, None),
}
# (e.g., read the data from the schema ...)
return res
# video.py
from ._base import BaseEmbedView
class EmbedView(BaseEmbedView):
# ./video-embed.pt
def __call__(self):
res = BaseEmbedView.__call__(self)
# (several additions for videos)
return res
I tried as well to change the entries to a for="*" attribute and put the interface in an allowed_interfaces attribute instead, but this didn't work -- not very surprisingly, since there are many "embed" pages for the same for value.
How is this supposed to be done, please? Thank you!
The browser:page directive will use its template attribute to define an attribute on the view class (I think the name of this attribute is index). The base __call__ will use this attribute to "render" the view. If you override __call__ in your class, the your __call__ will render the view (and apparently ignores the template attribute).
Background: A browser:page registers a view. Technically, a view is a (multi) adapter for an object and a request. During the adaptation, the adapter is (always) called on the objects (for a class instance, this means that its __call__ method is called).
Ah, thank you. I somehow had the imagination of __call__ being the method to provide the data.
That is obviously incorrect.
For the @@embed views, which make use of a template each, I changed the names of the __call__ methods to data and use view/data now in the templates instead of view.
Thus, the general rule seems to be:
If not using a template, override the __call__ method of the used BrowserView subclass
(I have created a @returns_json decorator for my @@ajax-nav views; perhaps there is such a beast elsewhere already, but it was easy enough);
Otherwise, take care not to override the __call__ method but create a method with another arbitrary name, e.g. data, and call this in the template to get the data (e.g., tal:define="data view/data").
Correct?
Is there a nice documentation link we could add here?
The typical interaction between view and template it that the view provides preprocessed data via appropriate attributes and/or methods - ready to use for the template with the aim to separate logic from presentation: the class is responsible for the logic, the template for presentation. Thus, usually, you would not have a single method which provides all data but several individual attributes/methods for individual values (to keep the template as simple as possible).
E.g., I have an optval attribute in my objects; if it is non-empty, I'd like to use a pre-processed optval_pretty value in the template.
As for the logic, I suppose a simple