Use the same view in multiple models

Author:Peter Bengtsson

If you have multiple models each with their own views, perhaps you want all views to have access to one view in common.

Purpose

You want all views in all models of an application to have access to a view without having to redefine this view in each model. For example you have a master template that defines the viewlet managers or METAL macros and you want all “sub views” to be able to use this.

Prerequisities

Suppose you have a simple Grok application up and running and you’ve defined another model other than the application one called Term in a file called term.py like this:

## app.py

class App(grok.Application, grok.Container):
   pass

class Index(grok.View):
   # see app_templates/index.pt
   pass

class Master(grok.View):
   # see app_templates/master.pt
   pass

-------%<-----------------------------

## term.py

class Term(grok.Model):
   pass

class Index(grok.View):
   # see term_templates/index.pt
   pass

Now, the App model has two views: index and master. The Term model has only one view: index. In both files called index.pt it says something like this on the very first line:

<html metal:use-macro="context/@@master/macros/page">

That works fine for app_templates/index.pt but will give you a TraversalError if you try to do the same in term_template/index.pt.

Step by step

The solution is really simple. Basically, change the Master view to this:

from zope.interface import Interface

class Master(grok.View):
   grok.context(Interface)

With this you’ll be able to reach context/@@master in any of the templates of your application which achieves the goal. Think of grok.context(...) as a filter mechanism that attaches itself into the “namespace tree” of your application at a certain “branch”. By saying the context is Interface you’re almost attaching the view to the trunk of the trunk.

Further information

An alternative solution would be to use a base class and attach the Master view to that. Then you let all other models also subclass this base class and they get the shared functionality too. That approach has the advantage that it’s more “standard pythonic” but you’re then not using the powerful patterns that Grok offers plus you have to remember to add the base class on all other models which adds noise to the code.