我正在创建我的Plone站点的一个分叉(它已经很久没有分叉了(。该网站有一个用于用户配置文件的特殊目录对象(一种特殊的基于原型的对象类型(,称为portal_user_catalog
:
$ bin/instance debug
>>> portal = app.Plone
>>> print [d for d in portal.objectMap() if d['meta_type'] == 'Plone Catalog Tool']
[{'meta_type': 'Plone Catalog Tool', 'id': 'portal_catalog'},
{'meta_type': 'Plone Catalog Tool', 'id': 'portal_user_catalog'}]
这看起来是合理的,因为用户配置文件没有"正常"对象的大部分索引,而是有一小部分自己的索引。
由于我找不到如何从头开始创建这个对象,所以我从旧站点导出了它(作为portal_user_catalog.zexp
(,并将它导入到新站点。这似乎有效,但我无法将对象添加到导入的目录中,甚至无法显式调用catalog_object
方法。相反,用户配置文件被添加到标准portal_catalog
中。
现在我在我的产品中发现了一个模块,它似乎达到了目的(Products/myproduct/exportimport/catalog.py
(:
"""Catalog tool setup handlers.
$Id: catalog.py 77004 2007-06-24 08:57:54Z yuppie $
"""
from Products.GenericSetup.utils import exportObjects
from Products.GenericSetup.utils import importObjects
from Products.CMFCore.utils import getToolByName
from zope.component import queryMultiAdapter
from Products.GenericSetup.interfaces import IBody
def importCatalogTool(context):
"""Import catalog tool.
"""
site = context.getSite()
obj = getToolByName(site, 'portal_user_catalog')
parent_path=''
if obj and not obj():
importer = queryMultiAdapter((obj, context), IBody)
path = '%s%s' % (parent_path, obj.getId().replace(' ', '_'))
__traceback_info__ = path
print [importer]
if importer:
print importer.name
if importer.name:
path = '%s%s' % (parent_path, 'usercatalog')
print path
filename = '%s%s' % (path, importer.suffix)
print filename
body = context.readDataFile(filename)
if body is not None:
importer.filename = filename # for error reporting
importer.body = body
if getattr(obj, 'objectValues', False):
for sub in obj.objectValues():
importObjects(sub, path+'/', context)
def exportCatalogTool(context):
"""Export catalog tool.
"""
site = context.getSite()
obj = getToolByName(site, 'portal_user_catalog', None)
if tool is None:
logger = context.getLogger('catalog')
logger.info('Nothing to export.')
return
parent_path=''
exporter = queryMultiAdapter((obj, context), IBody)
path = '%s%s' % (parent_path, obj.getId().replace(' ', '_'))
if exporter:
if exporter.name:
path = '%s%s' % (parent_path, 'usercatalog')
filename = '%s%s' % (path, exporter.suffix)
body = exporter.body
if body is not None:
context.writeDataFile(filename, body, exporter.mime_type)
if getattr(obj, 'objectValues', False):
for sub in obj.objectValues():
exportObjects(sub, path+'/', context)
我试着用它,但我不知道该怎么做;我不能称之为TTW(我应该尝试发布这些方法吗?!(。我在debug
会话中尝试过:
$ bin/instance debug
>>> portal = app.Plone
>>> from Products.myproduct.exportimport.catalog import exportCatalogTool
>>> exportCatalogTool(portal)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File ".../Products/myproduct/exportimport/catalog.py", line 58, in exportCatalogTool
site = context.getSite()
AttributeError: getSite
所以,如果这是一条路,看起来我需要一个"真实"的背景。
更新:为了获得此上下文,我尝试了External Method
:
# -*- coding: utf-8 -*-
from Products.myproduct.exportimport.catalog import exportCatalogTool
from pdb import set_trace
def p(dt, dd):
print '%-16s%s' % (dt+':', dd)
def main(self):
"""
Export the portal_user_catalog
"""
g = globals()
print '#' * 79
for a in ('__package__', '__module__'):
if a in g:
p(a, g[a])
p('self', self)
set_trace()
exportCatalogTool(self)
然而,当我调用它时,我得到了与main
函数的参数相同的<PloneSite at /Plone>
对象,它没有getSite
属性。也许我的网站没有正确调用这样的外部方法?
或者我需要在configure.zcml
中以某种方式提及这个模块,但如何提及?我在目录树(尤其是Products/myproduct/profiles
下面(中搜索了exportimport
、模块名称和其他几个字符串,但什么也找不到;也许曾经有过一次整合,但被打破了。。。
那么我该如何使这个portal_user_catalog
工作呢?非常感谢。
更新:另一个debug
会话表明问题的来源是某些transaction
物质:
>>> portal = app.Plone
>>> puc = portal.portal_user_catalog
>>> puc._catalog()
[]
>>> profiles_folder = portal.some_folder_with_profiles
>>> for o in profiles_folder.objectValues():
... puc.catalog_object(o)
...
>>> puc._catalog()
[<Products.ZCatalog.Catalog.mybrains object at 0x69ff8d8>, ...]
CCD_ 17的这种群体并不持久;在debug
会话结束并开始fg
之后,大脑消失了。
看起来问题确实与事务有关。我有
import transaction
...
class Browser(BrowserView):
...
def processNewUser(self):
....
transaction.commit()
以前,但显然这还不够好(和/或可能做得不正确(。
现在,我用transaction.begin()
显式启动事务,用transaction.savepoint()
保存中间结果,在出现错误时用transaction.abort()
显式中止事务(try
/except
(,在成功的情况下,最后只有一个transaction.commit()
。一切似乎都正常。
当然,Plone仍然没有考虑到这个非标准目录;当我"清理并重建"它时,它后来就空了。但对于我的应用程序来说,它已经足够好了。