[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