[z3-five] PT has no attribute 'getPhysicalRoot'
Martin Aspeli
optilude at gmx.net
Sat Dec 9 00:11:45 CET 2006
Dennis Schulz wrote:
> I tried to subclass the DomainClass in alchemist from
> Acquisition.Explicit (and tried also Implicit) but still the same error
> messages like before.
> When I print out context.aq_chain then says that 'List' object has no
> attribute 'aq_chain'. So its useless in this case to get the aquisition
> context like that.
I'm struggling to follow your reports here, but just some general notes
on Acquisition and Five:
Anything you publish in Zope 2 really needs an acquisition wrapper. A
lack of such often manifests itself in odd security errors (like
username not found, or simply Unauthorized). Acquisition.Explicit will
normally do. Views generally need this - and this is what you get with
Products.Five.browser.BrowserView as a base class.
Sometimes, things expect to be able to acquire things implicitly. In
that case, Acquisition.Implicit is a better base class, but I try to
avoid it.
I've found in a few cases that I need to inherit from
OFS.SimpleItem.SimpleItem for things to work; this normally means that
the code is expecting to be a pretty fully-featured Zope 2 object (e.g.
it has a role manager). To be honest, this is like shooting pigeons with
cannons, but it's sometimes a useful thing to try, if just to see
whether you are missing some mix-in class.
If you have a browser view that mixes in Acquisition (as you nearly
always need to) then you may run into strange acquisition chain
problems. Normally, it goes like this:
from Products.Five.browser import BrowserView
class MyView(BrowserView):
def __init__(self, context, request):
self.context = context
self.request = request
def my_function(self):
# do something with self.context
Since you assigned context to self.context, and context is most likely a
Zope 2 object, then context has an inner acquisition chain based on
containment (aq_parent(context) is the parent object of the context
object in the containment hierarchy). However, the outermost acquistion
chain involves the MyView class, because it has Acquisition.Explicit and
anything you retrieve from it by attribute access gets wrapped in that
object.
So, aq_chain(self.context) will be something like MyContext - MyView -
aq_parent(MyView) ...; in most cases this is not what you really expect.
It normally works fine, until you do something with context that expects
a sane acquisition chain. Sometimes you can also get nested acquisition
chains, which is really nasty.
The most common solution is to always use aq_inner(self.context). I tend
do start most of my functions with:
from Acquisition import aq_inner
def my_function(self):
context = aq_inner(self.context)
# do something with context, not self.context
Another pattern, which you see in Plone (and which I dislike, but it's a
bit safer) is to do this:
def __init__(self, context, request):
self._context = [context]
self.context = context # you normally need this anyway
self.request = request
def my_function(self):
context = self._context[0]
Since self._context is a list, the items in that list are not
acquisition wrapped, so you're safe.
Anyway, I hope that helps a bit. It's normally quite instructive to
print aq_chain(context) in a debug session and see whether it looks sane
(normally, it should reflect containment and end with BaseRequest).
Martin
More information about the z3-five
mailing list