[Zope] - How to register an object?

Amos Latteier amos@aracnet.com
Wed, 13 Jan 1999 18:46:44 -0800


At 04:57 PM 1/13/99 -0500, Peter J Ulintz  wrote:

>Hi.
>Could you take a minute and help me out?

Sure, but I'm taking the liberty of ccing the Zope list so that hopefully
others will profit. I hope you don't mind.

>So I'm trying to publish an object in the Zope framework. 
>Here's the object
>
>person.py:
>-----------------------------------------------------------
>import DocumentTemplate
>
>class Person:
>    "A simple person"
>    def __init__(self, name):
>        self.name = name
>
>    index_html=DocumentTemplate.HTMLFile("my_template.dtml")
>------------------------------------------------------------
>   
>The "my_template.dtml" file is exactly the same as in the "Techical
>Introduction to Object Publishing" document.  Now, I want to publish the
>object in the Zope heirarchy using an External Method.  I used...
>
>import_person.py:
>-----------------------------------------------------------
>import person
>
>def add_person(self, name = 'John Doe'):
>    """This method is called by a folder to add a person"""
>    person=person.Person(name)
>    if not hasattr(self, name):
>        setattr(self, name, person)
>    return "Person added to folder"
>-----------------------------------------------------------

In general what you are doing is right--creating an objects and installing
it in the object hierarchy. Unfortunately, there is a subtle problems with
this. The problem is that your person object cannot be stored in the object
database since the External Method machinery makes the Person class hard to
unpickle. If you were creating Zope objects, or if the Person class existed
somewhere else, like in the Shared module, this approach would work. I
believe this limitation is mentioned in the External Method documentation.

>So, I create an External Method-- ID: addPerson  Title: Add Person
>Function Name: add_person	Python module file: import_person
>This creates an external method object in my Zope folder called
>"addPerson".  If I now go to the browser and type(I'm using the
>ZopeHTTPServer)...
>
>http://141.214.57.234:9673/addPerson?name="Geddy"

OK, here's another problem. No need for quotes around Geddy. In fact those
quotes are going to cause you problems.

>...I get the response, "Person added to folder".  But I'm not sure what's
>SUPPOSED to happen here.  Is the object supposed to magically appear in
>the folder?  What am I doing wrong?  Just typing:
>http://141.214.57.234:9673/addPerson
>works, but typing 
>http://141.214.57.234:9673/addPerson?data="bullocks"
>gives the same "Person added to folder" message.

OK, Zope is doing exactly what you are telling it to do. It is creating an
object, installing it in a folder and returning a message. I'm not sure
what else you want ;-)

If you want a Zope object to appear in the management interface after this,
you need to install a Zope object, not just a random object. For an object
to be manageable through the web with Zope's interface it must support the
Zope Product API.

Also installing a Zope Product in a Folder should in general be
accomplished with the '_setObject' method, not a plain old 'setattr'.

>How do I publish an actual "Geddy" person object, that I can call the
>index_html attribute on?  Oh, following your suggestion (and the one in
>the External Methods documentation on the site), creating a file

OK, the essential functioning of the Zope ORB is to allow you to use URLs
to traverse the object hierarchy. So if you call

myFolder/addperson?data=duke

Then your External Method will add an attribute named 'duke' to 'myFolder'.
Therefore you should now be able to access this attribute like so

myFolder/duke

Make sense? To publish an object you point your browser at its URL.

>import_person2.py:
>--------------------------------------------------------------
>
>import person
>
>def addPerson(self, name='Dufus'):
>    "return person"
>    return person.Person(name)
>-------------------------------------------------------------
>
>Trying the same thing gives a "Sorry, th requested document does not
>exist" error.  The page source doesn't really tell me much there.

Ouch! My bad! This method does not *publish* a Person instance, it
*returns* a Person instance as a response. So Zope tries to understand the
instance as a string and decides that it is not a valid response.

(Actually viewing the source of the error page should give you some
information about what went wrong. That's how I discovered my mistake.)

To actually publish an object, it must be part of the object hierarchy so
that Zope can traverse it.

Let me give a good example here:

The first thing we'll do is create a module to hold our publishable
classes. Lets create our own package inside the Shared package. Create a
directory inside lib/python/Shared named PeeWee (or use your own name).
Next create an empty file __init__.py inside the PeeWee directory. This
lets Python know that PeeWee is a package. Now let's create a Python file,
PlayHouse.py inside the PeeWee directory.

class PlayHouse:
  "Play house"
	
  def index_html(self,game='tag'):
    "publish the playhouse"
    return "In the play house we play %s." % game

OK, now we have a publishable class that is Zope accessible. Now we need to
get an instance of that class into the object hierarchy. Let's use an
external method. Create a Python file in Extensions named peewee_utils.py

from Shared.PeeWee.PlayHouse import PlayHouse

def addPlayHouse(self,id):
  "Add a playhouse to the current folder"
  if not hasattr(self,id):
    setattr(self,id,PlayHouse())
    return "playhouse added with id %s" % id
  else:
    return "id %s already in use" % id

Now create an External Method object to give us access to the addPlayHouse
method. Suppose we give our External Method the id 'addPlayHouse', and tell
it to use the 'addPlayHouse' method of the 'peewee_utils' module.

OK, now we can call our method and install a publishable object in the Zope
object hierarchy.

myFolder/addPlayHouse?id=myHouse

This should return "playhouse added with id myHouse". What the method did
was create a PlayHouse instance and make it an attribute of the myFolder
object. Now we can access the PlayHouse like this:

myFolder/myHouse?game=hide+and+seek

Which should return "In the play house we play hide and seek."

Note that you will not see any PlayHouse object in the management screen.
This is because it is not a Zope Product. However, you can indirectly sense
that it is there--if you try to create a Document with id 'myHouse' you
will be told that 'myHouse' is already in use.

I hope this helps. (I'll update the docs on the Zope site.)

>Lastly, trying your External Objects product, and importing the "Person"
>object from the person.py, creates on External Object in the Zope folder.
>Directing my browser to that brings up the folder's index_html page, no
>matter what I put as an arguement.  How do I use that?  

The External Object Product is a container for externally defined
publishable objects. You need to tell the External Objects Product the
names of the objects you want to publish and the module they reside in.

So for example if you define an object 'person' in a module 'Person' in the
Extensions directory you need to let External Objects know these facts.
Once you have configured your External Object object, access the external
objects as sub-objects of the External Objects object like so:

myExternalObjects/myObject

Note: your published objects may contain further sub-objects.

Hope this helps. Object publishing takes a little while to grasp. Don't
give up!

-Amos

P.S. A final note of advice. If you are just learning object publishing--I
would advise not trying to plug your objects into the Zope framework right
away. Try publishing your own modules with ZopeHTTPServer.py. Get a feel
for how to composite objects and how they map to URLs. Then figuring out
how to get your objects to play in the Zope framework will make more sense.