ZCA在Plone应用之三:用catalog搜索
ZCA在Plone应用之三:用catalog搜索
http://www.315ok.org/blogfolder/580
http://www.315ok.org/logo.png
ZCA在Plone应用之三:用catalog搜索
ZCA在Plone应用之三:用catalog搜索
[align=left]使用catalog搜索对象(Searching for objects using the catalog)[/align][align=left] 至今,我们已经讨论了ZODB的object graph。使用字典协议来检索acquisition-wrapped对象,我们可以walk this graph;使用诸如keys()和values()的方法。第一个方法会返回那个container中所有的IDs,第二个方法会返回一列contained objects,这样我们可以浏览folderish对象。[/align][align=left] 每次检索整个ZODB来获取我们想要的对象是不明智的。一般来说,像values()函数,应尽可能避免,因为它会从ZODB中唤醒大量的数据——从磁盘中读取出来,并放置在缓存中。这对于大的数据集会有更显著的影响。[/align][align=left] Zope使用ZCatalogs来缓和这个问题,这个很像数据库中对象表。在Plone中,有一个ZCatalog,名字是portal_catalog,它位于站点的根目录,我们可以如下方式应对:[/align]
[/align][align=left] 在这些例子中,pbass是basses的孩子,那就是为什么当在guitars目录下搜索所有项目时它被显示,而只当搜索guitars目录下的直接项目时,它不被显示。也注意到,没有深度限制的话,guitars文件夹被列为搜索结果,但当深度为1(即直接位于folder文件夹下的项目)时,它却不被包括。[/align][align=left] 使用特殊的参数sort_on和sort_order,我们可以控制返回值的序列,使用sort_limit能够控制返回值的最大数量。当使用sort_limit时,我们可以潜在的获取一些项,它仅仅预示着搜索算法,the lazynature of the returned list makes it possible that complex searches will causethem to overshoot a little.因此,we normally alsoexplicitly limit the number of items we iterate over: [/align]
[/align][align=left] 函数reindexObject()来自CMFCatalogAware mix-in class,几乎在所有的内容对象上使用。[/align]它告诉目录去重新索引给出的对象。不提供参数的话,它会对所有索引值进行索引,但是如果我们没有任何改变的话,那么通过传递一列将要索引的索引值,可以省去很多进程。but we can save a bit of processing by passing a list of indexes toreindex if we are certain nothing else has changed.也有reindexObjectSecurity(),它将为当前对象和其孩子自动刷新权限相关的索引。
>>> from Products.CMFCore.utils import getToolByName >>> catalog = getToolByName(context, 'portal_catalog')[align=left]这里,context必须是Plone站点或Plone根站点本身中的一个对象。[/align][align=left] [/align][align=left] 目录用indexes和metadata来进行配置,前者能够用来搜索索引对象的多种属性,后者是一些确定的属性的拷贝。其中,这些确定的属性在不用查询默认的内容对象条件下被检查。有时候,一个属性会被同时使用在indexes和metadata中。你可以把索引当做一个你可以找到某一个对象的事物,把metadata当做可以检查查询结果的事物。(You can think of an index as something you use to find an object,and a metadata item as something you use to inspect the search results.)[/align][align=left]Where an object does notprovide a particular attribute, the value of any corresponding metadata itemmay be Missing.Value (or it could be acquired from a parent).[/align][align=left]笔记:Iftoo many attributes are listed in the metadata table, the catalog will grow insize and become slower, counteracting the efficiency benefits of using metadatainstead of fetching full objects. [/align][align=left] 为了查看metadata列的所有列表,查看Metadata表下的portal_catalog。索引被列在了Indexes表下。下一章节我们会看到这样一个例子:通过catalog.xml的导入步骤,添加额外的索引和metadata列。[/align][align=left] Plone的目录applies an implicit search parameter,这样确保了只有那些对当前用户可见的内容对象才被返回,而非内容对象(例如,CMF tools found in the portal root)不被索引化,所以当进行目录搜索时,不被查询。[/align][align=left] [/align][align=left] 笔记:If you want to find objectswhich are not viewable by the current user, you can use theunrestrictedSearchResults() function of portal_catalog. In Restricted Python(see next), use of this function is usually restricted to the Manager role.[/align][align=left] 当我们搜索目录时,它返回一个被称为catalog brains 的lazy list。Catalogbrains有metadata表中不同列值组成的属性。Brains也包含一些有用的方法,用来检查那些被目录化的对象。更重要的是,检索一个catalogbrain不会唤醒索引化的内容对象本身。为了取得整个对象,我们可以使用方法getObject()。[/align][align=left] 关于ZCatalogs的更多信息,查看Zope书中Searching and CategorizingContent chapter章节,可以查看http://docs.zope.org/zope2/zope2book/.在接下来的章节中,你会看到使用目录和通读Plone源码的例子。下面是一些普通目录使用的例子:[/align][align=left]Toretrieve all published news items in the site, use:[/align]
>>> for brain in catalog(
... {'portal_type': 'News Item', 'review_state': 'published'}
... ):
... print(brain.getPath())
/plone/folder/guitars/strat
/plone/folder/guitars/lp
[align=left] 我们直接调用目录对象来执行一个查询。出于测试的目的,我们仅仅打印路径,由brain-specific getPath()返回。它就相当于在一个常规对象上使用'/'.join(obj.getPhysicalPath())。[/align][align=left] 为了改善这一点,我们使用getObject()来检索这样的一个对象。注意, 为了避免发生performance hit,我们将不会这样做:[/align]>>> for brain in catalog.searchResults(
... {'portal_type' : 'News Item', 'review_state' : 'published'}
.. ):
... print('/'.join(brain.getObject().getPhysicalPath()))
/plone/folder/guitars/strat
/plone/folder/guitars/lp
[align=left] 我们也使用方法searchResults(),它相当于调用目录对象。[/align][align=left] 方法getURL()和getPath()是互补的。它返回引用对象的URL值。像普通对象中的absolute_url()方法,它会将当前服务器的URL(这个值可能与server URL不同)考虑进来:[/align]>>> for brain in catalog(
... {'portal_type': 'News Item', 'review_state': 'published'}
... ):
... print brain.getURL() == brain.getObject().absolute_url()
True
True
[align=left] 不同类型的索引接收不同类型的查询参数。The most common kinds are the FieldIndex, which indexes a singlefield, and the KeywordIndex, used when a field contains a list of values and wewould like to be able to search for a subset of them.例如,Subject索引引用Dublin Core subject。为了找到所有对Guitars or Fender 进行引用的documents或news items,我们可以这样写:[/align]>>> results = catalog(
... {'portal_type': ('Document', 'News Item',),
... 'Subject': ('Guitars', 'Fender',)}
... )
>>> sorted([r.getId for r in results])
['fender', 'lp', 'tele']
[align=left] 这里有3个对象,fender, lp, 和 tele,它们匹配于查询条件。我们也使用了getId的metadata attribute(which stores the return value ofthe method with the same name)。并且reduce the lazy listof results to a sorted list of string IDs for the purposes of validating theoutput reliably。[/align][align=left] 路径索引能够通过位置用来搜索对象。默认情况下,它会匹配指定路径和所有的子路径。通过向索引传递一个带有键query和depth的字典,我们可以查询深度为零或为1的路径:[/align]>>> guitarsPath = '/'.join(folder['guitars'].getPhysicalPath())
>>> results = catalog({'path': guitarsPath})
>>> sorted([r.getId for r in results])
['basses', 'fender', 'guitars', 'jagstang', 'lp', 'pbass', 'strat', 'tele']
>>> results = catalog({'path': {'query': guitarsPath, 'depth': 0}})
>>> sorted([r.getId for r in results])
['guitars']
>>> results = catalog({'path': {'query': guitarsPath, 'depth': 1}})
>>> sorted([r.getId for r in results])
['basses', 'fender', 'jagstang', 'lp', 'strat', 'tele']
[align=left][/align][align=left] 在这些例子中,pbass是basses的孩子,那就是为什么当在guitars目录下搜索所有项目时它被显示,而只当搜索guitars目录下的直接项目时,它不被显示。也注意到,没有深度限制的话,guitars文件夹被列为搜索结果,但当深度为1(即直接位于folder文件夹下的项目)时,它却不被包括。[/align][align=left] 使用特殊的参数sort_on和sort_order,我们可以控制返回值的序列,使用sort_limit能够控制返回值的最大数量。当使用sort_limit时,我们可以潜在的获取一些项,它仅仅预示着搜索算法,the lazynature of the returned list makes it possible that complex searches will causethem to overshoot a little.因此,we normally alsoexplicitly limit the number of items we iterate over: [/align]
>>> results = catalog(
... {'portal_type': 'Document', 'sort_on': 'sortable_title'}
... )
>>> [r.Title for r in results]
['Favorite guitars', 'Fender', 'Precision bass']
>>> results = catalog(... {'portal_type': 'Document', 'sort_on': 'sortable_title',
... 'sort_order': 'descending'}
...)
>>> [r.Title for r in results]
['Precision bass', 'Fender', 'Favorite guitars']
>>> limit = 5
>>> results = catalog(
... {'portal_type': 'Document', 'sort_on': 'sortable_title',
... 'sort_limit': limit}
... )[:limit]
>>> [r.Title for r in results]
['Favorite guitars', 'Fender', 'Precision bass']
[align=left]它返回最后5个published对象,由title来分类。参数sort_order可以是"ascending"或者"descending",with "reverse" beingan alias for "descending"。The sortable_title index is a special version of the Title indexwhich uses some clever string manipulation to make sure that titles will sortthe way people normally expect them to.[/align][align=left] 当对象改变时,它们为了更新目录必须被重新索引。当通过Plone用户接口操作内容时,更新目录是被自动完成的。然而,当代码发生改变时,我们有时需要手工重新建立索引:[/align]>>> folder['favorites'].setDescription("Contains a list of favorites")
>>> len(catalog({'Description': "list of favorites"}))
0
>>> folder['favorites'].reindexObject(idxs=['Description'])
>>> len(catalog({'Description': "list of favorites"}))
1
>>> folder['favorites'].setDescription("My favorites!")
>>> folder['favorites'].setTitle("My favorite guitars")
>>> folder['favorites'].reindexObject()
>>> len(catalog({'Title': "My favorite guitars"}))
1
[align=left][/align][align=left] 函数reindexObject()来自CMFCatalogAware mix-in class,几乎在所有的内容对象上使用。[/align]它告诉目录去重新索引给出的对象。不提供参数的话,它会对所有索引值进行索引,但是如果我们没有任何改变的话,那么通过传递一列将要索引的索引值,可以省去很多进程。but we can save a bit of processing by passing a list of indexes toreindex if we are certain nothing else has changed.也有reindexObjectSecurity(),它将为当前对象和其孩子自动刷新权限相关的索引。