Reusing value from view template in a viewlet

Hi all,

For my custom dexterity content type, I have a view template which pulls some REST data. This content type includes a viewlet in the below-content-body area, which also needs access to the same data.

My first approach was to include the whole bodytext slot from main_template and defining my template variable there. This failed.

I am now trying to understand the documentation on viewlets which mentions Re-using code from a View - which leads me to believe that in my viewlet update() method, I can access functions defined in the code of my view but not variables defined in the template.

Is what I want possible? Hints appreciated...

I would write a common function, or class with the REST pull logic (maybe registered as utility or adapter depends on if needed) and use it in both.

Another way is to derive from a base-class implementing the logic and inherit from it in the view and viewlet.

More complex ones: 1) use a zope.contentprovider or 2) provide a macro or 3) provide a view just rendering the inner area and call it in the outer view/viewlet or 4) work with mosaic and tiles.

Many roads lead to Rome.

1 Like

Thank you @jensens - I'm going to try with a content provider and see if I can reuse my data as suggested here https://zopecontentprovider.readthedocs.io/en/latest/tales.html#additional-data-from-tal

1 Like

Question: Could one just use the same class (py-file) for both the viewlet and the view and 'memoize it (the def)' ?

memoize on the view takes the view instance into account

So either you write your own decorator (memoize on request, like for ram but only in the current request-response life-cycle) or use the ram cache with a custom key.

Writing an own decorator is not difficult. IMO a memoize.request would be a good addition to plone.memoize anyway (any takers?).

class Base(object):

    @memoize.ram(customkey)
    def foo(self):
        # ... do calc
        return heavycalculationthing


class SomeView(Base, BrowserView):

    pass


class SomeViewlet(Base, ViewletBase):

    pass

I ended up moving my REST query to the python view, this allows using __parent__ in the viewlet update() function.

class ProductItemView(BrowserView):

    def __call__(self):
        self.json_results = get_rest_results(url=some_url)
        return super(ProductItemView, self).__call__()

class ResultsViewlet(ViewletBase):

    def update(self):
        self.points_of_sale = self.__parent__.json_results.get('pos_attributes', {})
1 Like