[Zope] Weired catalog_object problem in python product

Grégoire Weber gregoire.weber@switzerland.org
Tue, 19 Dec 2000 13:51:31 +0100


Hi,

I read about ZCatalog been _the_ method of managing and searching objects 
in the ZODB. So I decieded to do searches and lists of object using ZCatalog.

After reading all how-to's/API-doc about ZCatalog, a lot in mailings lists
and 
studying a lots of code (ZDiscussions, Squishdot, PTK) I tried to use
ZCatalog the
proper way.

But there is one problem I could not solve for about 8 hours of work.

A short description of what my code does:
   I have three classes (NewsManager, NewsItem and ContentFolder) caring
about 
   news items. If I am creating a news item, it's object gets saved and 
   cataloged in the content folder (the content inherits from ZCatalog). 
   The NewsManager object responsible about creating the news item is named 
   news and resides in the same directory as the folderish content object
does.
   So the directory structure is:
      /orgname/content (content object, inherits from Products.ZCatalog)
      /orgname/news    (NewsManager object, inherits from OSF.Folder)

Now the problem (for a step by step description see below):
   The news items are correctly created in the content folder. But the item is
   cataloged as it would reside in xxx/news/content (which does not exist).
   I use self.absolute_url(relative=1) (called by __uniqueCatalogId()) to 
   generate the catalog id (see manage_afterAdd below). It seems (for me)
that 
   some aquisition magic is going on. Later when I edit the news item
   (manage_editNewsItem called by manage_editNewsItemForm) there appears an
   additional catalog entry with the id xxx/content. 

   Now there are two catalog entries for one news item. If I delete the 
   news item manualy using the zope management GUI one of these catalog 
   entries will be deleted only.

Hints:
1) The following status message appears in zopes error log
   after having edited /orgname/news/content/20001219_news000022:
      2000-12-19T11:10:41 ERROR(200) Catalog uncatalogObject unsuccessfully 
      attempted to uncatalog an object with a uid of 
      /orgname/content/20001219_news000022.

2) It seems for me that the magic resides in absolute_url().

Does somebody know about a solution of this problem or have an additional 
hint about generating catalog id's (it's a requirement for me to have the 
/orgname/-info in the catalog id!)?

I'am a Zope newby, so forgive me errors that are obvious.

System and SW-Versions:
- WinNT4 SP6 US
- Zope 2.2.4 started manualy

Remark: It's all programmed in Python because I don't like GUI programming 
tools (click, click, ... :-( ). So I implement all logic in python (as a
Product).


>>>>>>>>> what I've done in the zope management GUI <<<<<<<<<<

   Create a news item:
      http://localhost:8080/up/news/manage_addNewsItemForm

   View Contents (content folder):
      http://localhost:8080/up/content/manage_main
      --> item 20001219_news000022 is listed and links to:
      --> item 20001219_news000022 is listed and links to:

http://localhost:8080/up/content/20001219_news000022/manage_editNewsItemForm

   View Cataloged Objects (content folder):
      http://localhost:8080/up/content/manage_catalogView
      --> content contains 1 record(s).
          NewsItem /up/news/content/20001219_news000022 (test item)
      ??? why catalogized with path containing /news/?

   Edit the item by clicking the link in Cataloged Objects:
   Edit the item by clicking the link in Cataloged Objects:

http://localhost:8080/up/news/content/20001219_news000022/manage_editNewsIte
mForm

   View Catalog Objects:
      http://localhost:8080/up/content/manage_catalogView
      --> content contains 2 record(s).
          NewsItem /up/news/content/20001219_news000022 (test item) 
          NewsItem /up/content/20001219_news000022 (test item edited)
      ??? why couldn't the old item be uncatalogized?
      ??? why the changed item is catalogized without /news/ path?
      !!! I think there is one answer to both questions!
      !!! Rem.: I'd like to have the items cataloged without /news/ in the
path.

   remarks:
      1) content is the folder containing all kind of items
      2) content is also a ZCatalog folder containing a Vocabulary



>>>>>>>>> Code snippets <<<<<<<<<<

   #----------------------------------------------------------------------
   # NewsManager.py
   #
   # The only functionality of NewsManager is adding a new newsItem. It 
   # builds a unique news item id and then calls the addNewsItem method of 
   # NewsItem.
   #----------------------------------------------------------------------
   class NewsManager(OFS.Folder.Folder):
       # ... some code

       def __init__(self, parentFolder, contentFolder):
           self.contentFolder = contentFolder
           self.newsCounter = 0
           return dbhelpers.instObject(self, parentFolder, "news")

       # ... unimportant another code

       manage_addNewsItemForm = NewsItem.manage_addNewsItemForm

       def manage_addNewsItem(self, title, abstract, location,
                              generator, prio, date_syn, date_pub,
                              REQUEST=None):
           "write news item in content folder"
           id =   time.strftime("%Y%m%d", time.localtime(time.time())) \
                + "_news%06d" % (self.newsCounter)
           self.newsCounter = self.newsCounter + 1

           return NewsItem.manage_addNewsItem(self.contentFolder, id, title,
                                              abstract, location,
                                              generator, prio, date_syn,
date_pub,
                                              REQUEST)

   #----------------------------------------------------------------------
   # NewsItem.py
   #----------------------------------------------------------------------
   class NewsItem(OFS.SimpleItem.SimpleItem):
       "A news item in the subscriptable news system."    meta_type =
"NewsItem"

       def __init__(self, **para):
           # ... set parameters, eg.:
           self.catalogFolder = para['catalogFolder']

       manage_editNewsItemForm = Globals.HTMLFile("newsitem_editform",
globals())

       def manage_editNewsItem(self, title, abstract, location,
                               generator, prio, date_syn, date_pub,
                               REQUEST=None):
           "Save changes to News Item"
           # ... save changed parameteres

           # recatalog object (rem.: self.catalogFolder is the catalog)
           try: self.catalogFolder.uncatalog_object(self.__uniqueCatalogId())
           except ValueError: pass
           self.catalogFolder.catalog_object(self, self.__uniqueCatalogId())

           # ... etc.

       def __uniqueCatalogId(self):
           return '/' + self.absolute_url(relative=1)

       def manage_afterAdd(self, item, container):
           # copied from ZDiscussions.py, see additional remarks there
           OFS.SimpleItem.SimpleItem.manage_afterAdd(self, item, container)
           self.catalogFolder.catalog_object(self, self.__uniqueCatalogId())

       manage_addNewsItemForm = Globals.HTMLFile("newsitem_addform",
globals())

       def manage_addNewsItem(parentFolder, id, title, abstract, location,
                          generator, prio, date_syn, date_pub,
                          REQUEST=None):
       "Save changes to News Item"
       # instanate object (parameters have to be set in NewsItem (and
before the
       # instanation of the object) because ZCatalog calls implicitely
manage_afterAdd.
       newsItemObj = dbhelpers.instObject(NewsItem(catalogFolder =
parentFolder,
                                                   abstract      = abstract,
                                                   location      = location,
                                                   generator     = generator,
                                                   prio          = prio,
                                                   date_syn      =
various.datestr2epoch(date_syn),
                                                   date_pub      =
various.datestr2epoch(date_pub)),
                                          parentFolder, id, title)

       if REQUEST is not None:
           return Globals.MessageDialog(title = 'Edited', message =
'<strong>%s</strong> has been edited.' % newsItemObj.id, action =
'manage_main')

   #----------------------------------------------------------------------
   # ContentFolder.py: folder containing content
   #----------------------------------------------------------------------
   class ContentFolder(ZCatalog.ZCatalog):
       "The news management system"

       def __init__(self, parentFolder, id, title=''):
           # initialize ZCatalog (content folder is a ZCatalog!)
           ZCatalog.ZCatalog.__init__(self, id, title)

           # index setup (id and title allready catalogued by ZCatalog)
           self._catalog.addIndex('abstract',  'TextIndex')
           # ... etc.

           # meta-data colums setup (id and title allready catalogued by
ZCatalog)
           self._catalog.addColumn('abstract')
           # ... etc.

           return dbhelpers.instObject(self, parentFolder, "content")

   #----------------------------------------------------------------------
   # dbhelpers.py
   #----------------------------------------------------------------------
   def instObject(obj, parent, id, title=''):
       """instanates an object in the ZODB
          obj = Object to instanate
          parent = parent folder object
          id = the id of the document
          title = title of the document (optional)"""
       obj.id=str(id)
       obj.title=title
       parent._setObject(id, obj)

   return parent._getOb(id) # == obj (see OSF/Folder.py)

_______________________________________________________
Grégoire Weber
Rigistr. 31
CH-8006 Zürich
Switzerland
phone:  +41-(0)1-361 66 11
mobile: +41-(0)79-44 11 457
mailto:gregoire.weber@switzerland.org
Gregi's Handy-Handhabung: http://www.topics.ch/greg/ghh