This Blog continues on http://aliafshar.github.io/blog

Sunday, November 05, 2006

Using multi-adapters a la Zope

As a brief discussion (and I should mention that this has nothing to do with a web application), you have an object and you want to look at it. Imagine you have gone the whole way with this concept and you have arrived at Zope. Zope contains mechanisms for definition, storage and manipulation of objects, all using Python.

So you have an interface:

from zope.interface import Interface, Attribute

class IFruit(Interface):
name = Attribute("""The name of the fruit""")

Ok, it's simple. Now you write a class that implements this, still simple.

class Fruit(object):
implements(IFruit)
def __init__(self, name):
self.name = name

Pretty good. You can store that in an object database like ZODB if you like, but we are going to think how to view it.

A view (in Zope terminology) is something that adapts (multi-adapts) a "context" and a "request". We don't really understand what a "context" is, so we are going to call it an "object". A request can be something like "edit" or "view".

So of course we need an interface for views to adhere to, and an interface for a request to adhere to. This is where interfaces stop being documentation niceties, and start being implementation nasties.

class IView(Interface):
def render():
"""Display what needs displaying"""

class IViewRequest(Interface):
user = Attribute("""The user that made the request""")

So imagine we implement a simple view (now remember this is nothing to do with a web application). The view will display Fruit objects.

from zope.component import adapts, provideAdapter, getMultiAdapter

class FruitView(object):
implements(IView)
adapts(IFruit, IViewRequest)

def __init__(self, fruit):
self._fruit = fruit

def render(self):
print self._fruit.name

# not forgetting to register the adapter with zope.component
provideAdapter(FruitView)

And also a request implementation that does nothing

class ViewRequest(object):
implements(IViewRequest)
user = None

And we are ready to go:

view = getMultiAdapter((Fruit('banana'), ViewRequest()), IView)
view.render()

gives you

banana