[Zope-dev] Using other than NullResource to handle HTTP PUT
Brian Lloyd
Brian@digicool.com
Tue, 1 Aug 2000 10:03:45 -0400
> I'm developing, in python, some classes whose instances to be
> published by Zope, one of which is folder-like, i.e. is can contain
> instances. I want HTTP PUT requests which will create new object
> instances within instances of this folder-like class to be handled by
> a PUT function I define. I cannot identify the "right" way to do
> this, or at least a way which doesn't involve hacking the standard
> Zope code to have my PUT function handle the operation.
>
> The normal behaviour of Zope appears to be to create an instance of
> the NullResource class and call the PUT function on that. This then
> proceeds to create a DTMLDocument, Image or File instance which is
> not what I need to happen; I want to have instances of one of my own
> classes created instead.
Hi Richard,
If you look at the OFS.ObjectManager.ObjectManager class,
you'll see that it overrides __getitem__ and returns a
NullResource object if the requested key is not found as
an actual subobject.
The reason for that is that for the purposes of WebDAV
(and plain old HTTP 1.1 PUT) we want traversal to a
non-existant URL to retrieve an object that can understand
a PUT command. To achieve this, we want to create a
NullResource "on the fly" and return it if a non-existant
subobject is requested. Note that we *only want this to
happen during URL traversal*.
To make this happen, we take advantage of the way that the
traversal machinery looks for subobject. Lets say you have
a URL /products/spam and that the publisher has already
found the 'products' object (which is a Folder-like object).
What the publisher does with the 'products' object to try to
find the 'spam' subobject is:
o see if the object has an '__bobo_traverse__' method, and
if so, call it passing the REQUEST and the name it is
trying to look up. The value returned from this method
will be used as the subobject. This gives container-like
objects a hook to return 'on the fly' objects.
o if no __bobo_traverse__, try to do a getattr() on the
object with the given name. If this succeeds, the result
is used as the subobject.
o if getattr() fails, try to do a getitem (object['name'])
to get the subobject. This gives container-like objects
another opportunity to provide a hook by implementing
an __getitem__ method to perform the name lookup and
return the right thing. The default implementation of
__getitem__ in ObjectManager provides HTTP PUT and DAV
support for containers:
def __getitem__(self, key):
v=self._getOb(key, None)
if v is not None: return v
if hasattr(self, 'REQUEST'):
request=self.REQUEST
method=request.get('REQUEST_METHOD', 'GET')
if not method in ('GET', 'POST'):
return NullResource(self, key, request).__of__(self)
raise KeyError, key
So - the short story is that the way you should go about
implementing a custom handler for your collections is to
override __getitem__ with your own custom handler. Your
handler probably could just subclass NullResource in
fact, overriding the PUT method to do what you want.
> btw am I alone in struggling to understand the python classes
> underlying Zope's operation and how these classes work/ineract? I've
> read a lot of source code but still feel I have only the vaguest
> grasp of the theory of operation of the whole thing. Ho hum.
You are certainly not alone :^) Any large codebase really
needs a "10,000 foot view" map to help people understand
the individual bumps in the terrain in context at ground
level. That is something that we are currently missing
with Zope (though there are "partial maps" around in the
form of UML models of certain parts like ZODB). That is
something I'd like to work toward on dev.zope.org in the
future.
Hope this helps!
Brian Lloyd brian@digicool.com
Software Engineer 540.371.6909
Digital Creations http://www.digicool.com