Benutzung des ++attribute++-Namespaces in Zope3
In Zope3 kann man Objekte auf Attributen anderer Objekte speichern, dabei gibt es aber einiges zu beachten.
Wenn man in Zope3 ein Objekt child in ein Container-Objekt parent legt kann man dieses in der URL über parent/child
ansprechen. Will man aber ein Objekt auf einem Attribut eines anderen Objektes speichern geht man folgendermaßen vor:
Einfachster Fall
interfaces.py
from zope.interface import Interface, Attribute
class IChild(Interface):
"Das Kind."
class IParent(Interface):
"Das Elter."
child = Attribute("Kind-Objekt")
impl.py
from persistent import Persistent
from zope.interface import implements
from zope.app.container.contained import Contained
from myproj.interfaces import IChild, IParent
class Child(Persistent, Contained):
"""Kindklasse."""
implements(IChild)
class Parent(Persistent, Contained):
"""Elternklasse, die Kind auf Attrbitut tragen soll."""
implements(IParent)
def __init__(self, *args, **kw):
super (Parent, self).__init__(*args, **kw)
child = Child()
self.child = child
child.__parent__ = self
child.__name__ = '++attribute++child'
Wenn man von child zu parent traversieren können will, müssen __parent__ und __name__ gesetzt sein. In __parent__ steht das Elter in der Hierachie (also self). In __name__ steht, wie von parent zu child traversiert werden kann. Der Präfix '++attribute++' vor dem Attributnamen ist wichtig, damit der Traversierer weiß, wo er nach dem attribut suchen soll. (Das ist besonders wichtig, wenn parent ein Container ist, da dort eine Traversierung ohne Angabe eines Namespace-Präfix immer in den Container hineintraversiert und damit child nicht finden kann.)
Benutzung von UIDs
Wenn man für child eine UID benötigt, muss man child selbst beim UID-Utility registrieren und beim Löschen von parent selbst wieder dafür sorgen, dass die UID für child gelöscht wird (das wird sonst beim Hinzufügen und Löschen im Container automatisch über Events erledigt). Das Zope3-UID-Utility erwartet, dass ein Objekt für welches es eine UID generieren soll in einem Kontext eingebunden ist, der bis zur Wurzel zurückverfolgt werden kann. Also scheidet die Variante child im __init__ von parent anzulegen aus, da parent zu diesem Zeitpunkt noch keinen Kontext hat. (Es würde eine NotYet-Exception auftreten.)
An interfaces.py ändert sich nichts. impl.py ändert sich wie folgt:
from persistent import Persistent
from zope.app.container.contained import Contained
class Child(Persistent, Contained):
"""Kindklasse."""
class Parent(Persistent, Contained):
"""Elternklasse, die Kind auf Attrbitut tragen soll."""
child = None
In der configure.zcml wird für die Events IObjectAddedEvent und IObjectRemovedEvent ein Subscriber eingetragen:
<subscriber
for="zope.app.container.interfaces.IObjectAddedEvent"
handler=".eventhandler.onObjectAdded" />
<subscriber
for="zope.app.container.interfaces.IObjectRemovedEvent"
handler=".eventhandler.onObjectRemoved" />
In eventhandler.py benötigt man dann folgende zwei Funktionen:
import zope.event
from zope.app.intid.interfaces import IIntIds
from zope.app.container.contained import ObjectRemovedEvent
from myproj.interfaces import IParent
from mypro.impl import Child
def onObjectAdded(event):
obj = event.object
if IParent.providedBy(obj):
child = Child()
obj.child = child
child.__parent__ = obj
child.__name__ = u"++attribute++child"
uid_util = zapi.getUtility(IIntIds, context=obj)
uid_util.register(child)
def onObjectRemoved(event):
obj = event.object
if IParent.providedBy(obj):
zope.event.notify(ObjectRemovedEvent(obj.child, obj, obj.child.__name__))
onObjectAdded sorgt für die Initialisierung und Registrierung von child am UID-Utility.
onObjectRemoved teilt per Event mit, dass mit parent auch child gelöscht wurde. Das UID-Utility lauscht an diesem Event und löscht entsprechend die UID für child.
- Category(s)
- Zope 3
- The URL to Trackback this entry is:
- http://blog.gocept.com/benutzung-des-attribute-namespaces-in-zope3/tbping