Listing folder contents, accessing portal root and site tools
Portal item storage
All items are stored in the portal hierarchically.
You can use normal Python attribute accessing to navigate in the portal using object ids. Attributes are transparently mapped to Zope objects. Also, object ids form the url of the object. Python interfaces don't differentiate between child objects and fields.
For example, to refer this How-to one could use following code in a script running at plone.org:
# you have obtain to plone.org portal root object somehow and it's # stored in local variable "portal" documentation = portal.documentation howTos = getattr(portal, "how-to") # note that we need use getattr because dash is invalid in syntax myHowTo = getattr(howTos, "manipulating-plone-objects-programmatically")
Listing folder items
Method contentItems is defined in CMFCore/PortalFolder.py. See source code for details, e.g. filtering and other forms of listing.
items = folder.contentItems() # return Python list of children object tuple (id, object)
Listing objetcs like this is very very costly. You should avoid it always as possible. Read more about this in "waking up objects" in Plone core reference.
Listing folder items of certain types
Method listFolderContents retrieves the full objects in the folder (slow). It takes contentFilter argument. contentFilter argument is a dictionary and supports "portal_type" filter, which is a list of allowed portal types.
# List all types in this folder whose portal_type is "CourseModulePage"
return self.listFolderContents(contentFilter={"portal_type" : "CourseModulePage"})
Getting folder item ids
If you need to get ids only, use objectIds()method. This is permormance wise.
# Return a list of object ids in the folder ids = folder.objectIds()
Checking for the existence of a particular object id
If you want to know whether the folder has a certain item or not, you can use the following snippet. It's optimal code, but you can simplify it if you don't need to check if the folder is BTreeFolder.
# Use the BTreeFolder API if possible
if base_hasattr(context, 'has_key'):
# BTreeFolder's has_key returns numeric values
return context.has_key('index_html') and True or False
elif 'index_html' in context.objectIds():
return True
else:
return False
Acquisition
For many things Plone uses a mechanism called acquisition. It's like inheritance in class tree, but acquisition receives attributes using object context hierarchy. Children can override parent container properties. Most likely you will deal with acquisition behavior when setting permissions and properties. Usually you don't need to call acquisition methods directly.
For example,
- left_slots and
right_slots properties controlling shown portlets are accessed via
acquisition. left_slot and right_slot are initially declared in the
portal root. Child folders can override settings to define their own
portlets.
- One can limit/allow different permissions hierarchially in Plone. Acquisition is the base behind this security mechanism.
For dealing with permissions, see Zope's AccessControl module documentation (source code).
For dealing with properties, see Zope's the documentation (source code) of PropertyManager class in Zope's OFS module.
Getting content parent container
You can travel content hierarchy backwards using acquistions.
from Acquisition import aq_parent parent = aq_parent(context)
In some cases you might want to do parent = ac_parent(ac_inner(context)). Please could someone define difference between these two different use cases.
Getting portal root handle
The portal root in Plone code is referred as portal object.
In quick install script function install(self), the parameter self is handle to the portal.
In unit tests, you have self.portal.
If you don't have direct portal variable, you can acquire portal root using portal_url tool and acquistision.
from Products.CMFCore.utils import getToolByName # you know some object which is refered as "context" portal_url = getToolByName(context, "portal_url") portal = portal_url.getPortalObject()
Getting Zope application server handle
Sometimes you want to mess directly with Zope application server instead of staying within your Plone site instance. To get the Zope root, use the following code:
app = context.restrictedTraverse('/')
Portal tools
Often you need to access tool and utilities instances which are under portal root. These are like portal_types (for type information) and portal_membership (logged in information). A function called getToolByName can retrieve these utility instances for you.
from Products.CMFCore.utils import getToolByName
# In content method
def getMySecretVariabl(self)
plone_utils = getToolByName(self, "plone_utils")
# or in skin script
plone_utils = getToolByName(context, "plone_utils")