[Zope3-Users] Re: URL Traversal/SelectedManagementView

Jeff Rush jeff at taupro.com
Tue Jan 17 06:41:55 EST 2006


David Johnson wrote:
> 
> I want to create an instance of a class that does not reside in the Zope 
> DB, and yet manage it through the ZMI.

Yes, I'm working on that as well.


> That is what I have done so far.  I created a package called 
> “customers”, which has an instance in the Zope DB.  It has a view which 
> lists all customers from an RDBMS. It creates a link for each customer 
> with the customer ID embedded in it.
> 
> I would like to create, on the fly, a customer instance from the 
> customer ID in the URL.  Based upon the ID I could set all the 
> attributes of the instance by loading it from a database.

Hmm, I didn't try your approach, sorta faking it with record ids inserting 
the view construction.  My approach was to create a container component 
representing the SQL table and another component representing instances of 
records within that table.

class VentureSet(
     Persistent, SiteManagerContainer, Contained, SimpleSQLTable):

class Venture(
     Location, RelationalRow):

While the container, VentureSet, is persistent within the ZODB, what it 
*contains* is constructed dynamically from SQL queries.  The ZODB persistent 
data is just the connection name itself, nothing more, and the SQL table 
name is a class-static attribute.  Between those two, each XXXSet class can 
find its data table.

   def keys(self):
       """Return a sequence-like object containing the names
          associated with the objects that appear in the folder
       """
       query = "SELECT v_id FROM %s WHERE subset = '%s'" \
             % (self.__sqltable__, self.subset)
       return [row.v_id for row in self(query)]
 
 


The call to self is something I clipped from SQLMethods, to convert the 
connection name into an actual connection object, doing a utility lookup, 
submitting the query and returning the records:

     def __call__(self, query):
         try:
             connection = self.getConnection()
         except KeyError:
             raise AttributeError, (
                 "The database connection '%s' cannot be found." % (
                 self.connectionName))
 
 

         cache = getCacheForObject(self)
         location = getLocationForCache(self)
         if cache and location:
             _marker = object()
             result = cache.query(location, {'query': query}, default=_marker)
             if result is not _marker:
                 return result
         result = queryForResults(connection, query)
         if cache and location:
             cache.set(result, location, {'query': query})
         return result


Here is where a query to the VentureSet container wraps the rows read from 
the SQL table into Zope 3 components:

     def values(self):
         """Return a sequence-like object containing the objects that
            appear in the folder.
         """
         query = "SELECT * FROM %s WHERE subset = '%s'" % 
(self.__sqltable__, self.subset)
         ventures = []
         for row in self(query):
             venture = Venture(row.v_id, row.legalname, row)
             locate(venture, self, row.v_id)
             ventures.append(venture)
         return ventures
 
 

The instances of Venture, which represent the records in the table are 
non-persistent as far as the ZODB goes.  I did inhert from Location so that 
they have a name (primary key) and location (ref to the VentureSet 
container) but those attributes are assigned after an SQL query to 
instantiate the object.

   class Venture(Location, RelationalRow):

The RelationalRow class is my own little lazy accumulator of set-attributes 
that get turned into an UPDATE SQL statement at commit time, using:

   transaction.get().beforeCommitHook(self.writeMyUnwrittens)

This all gives me a ZMI-manageable object folder of SQL records, and the 
URLS look something like (I have similar ledgerset/ledger component pair 
underneath the vntureset/venture pair):

   http://www.taupro.com/venture/IBM/ledger/100

One trick with this is you have to provide a NameChooser class, from 
Philipp's Zope 3 book, to have the VentureSet container defer to the Venture 
item for its name, since in Zope 3 items can have names that differ from the 
name by which it is known within its container.  The NameChooser class is 
straight from the book.

I hope this answers your question and if not, I'm glad to share my sourcecode.

I'm looking now at whether I should abandon my home-grown ORM and switch to 
sqlos/SQLObject although for what little mine does so far, it's much simpler.

-Jeff



More information about the Zope3-users mailing list