Personal tools
You are here: Home Documentation How-tos Add Content from Python
Support

Get Help

Join our chat rooms or support forums if you have more specific questions.

Plone Training
Learn how to design, build, and deploy a website in Plone through one of the numerous Plone training sessions around the world.
Find Plone training…
 
Document Actions

Add Content from Python

This How-to applies to: Any version.
This How-to is intended for: Developers

If you're writing Python code to customize your site, you may need to create content objects programmatically. It's not hard.

When you want to add content, there are three things to consider: where, which type of content, and the properties of the object we create.

Where

The most common place to add content is "here"; that is, the folderish object which is our current context. This is how we add content in the UI: we visit a Folder (or similar) and select the type to add. In Python, this is named either context in a Python Script or Page Template, or as self in product code.

You can use self or context directly of course, but we'll bind it to the name container (you'll see why shortly):

    container = context

Or (in product code):

    container = self

(From here on, we'll use context like in a Python Script; make the substitution if you're in product code.)

But what if you want the content somewhere else? Well, you just get a handle on the folderish object you want. There are lots of ways to do this. Often we want to put it in a subobject of something we already have a handle on. We can use attribute notation:

    container = context.dogs

Of course, you must be careful in doing this that what you ask for does exist, or else you'll get an AttributeError. We can use getattr to get around this:

    container = getattr(context, 'dogs', None)

This will just result in None, Python's null value, if dogs is not present in the container. You can use an if or boolean statement to decide what to do then. This is much better than just failing with a exception. (This one is also good if the name has dots or dashes or other characters that would confuse Python.) Remember that acquisition is in effect here!

There is also mapping access (sometimes called "subscript") notation:

    container = context['dogs']

This one is a little different, in that it checks only direct containment. In other words, no acquisition.

You'll notice that in the last two cases, we use a string. It doesn't have to be hardcoded:

    subobj = context.REQUEST.pickObj   # or any other way we can get a string!
    container = context[subobj]

You are not, of course, limited to one level:

    container = context.dogs.retrievers

And you can even go to your parent:

    container = context.aq_inner.aq_parent

Here's a sibling:

    parent = context.aq_inner.aq_parent
    container = parent.plants

Sometimes you want to do an "absolute path". We can get a handle on the Plone Site object and traverse from it:

    from Products.CMFCore.utils import getToolByName
    urltool = getToolByName(context, 'portal_url')
    portal = urltool.getPortalObject()
    container = portal.animals.dogs.retrievers

There are other ways, too. Other methods you can call will return an object (like portal_membership.getHomeFolder). There is also restrictedTraverse, the getObject method on catalog results, and other ways you might find.

So by now you've decided where to put your content (which, for the purpose of the next section, we'll just assume is container). Now we need to put something in it!

Creating Content

It is easy to create content in a place we have a handle to: we are provided, through acquisition, a factory method. A factory, just like it sounds, is a method that is responsible for creating objects. We give this factory the name of the type of content we want to create (and some other info) and it does the rest. The method is 'invokeFactory':

    id = "nowHearThis"
    container.invokeFactory(type_name="News Item", id=id)

The type_name is the name of the content Type you want to create. Note that this is the id of the object you see in the portal_types tool, which may not be the same as the name you see in the Plone UI (which uses the type's title, if available.) The id is the "short name" of the new object, which you will see in the URL.

Note that invokeFactory will obey restrictions on creation, as set in the types tool ("implicitly addable" and filters.) You can go a little lower to bypass this restriction with the Types Tool's constructContent method, which invokeFactory uses:

    typestool = getToolByName(context, 'portal_types')
    typestool.constructContent(type_name="News Item", container=container, id=id)

These methods will also accept other parameters, which will be passed on to the object's constructor method. You can use these if you know the constructor; title is fairly common.

If you want to create a non-content object (like something Zope-specific), you have to do it another way. Look for manage_addProduct.

Working with Content

So we've created some content, but it's basically empty. To work with it, we must get a handle on it:

    obj = container[id]

will work. You can use its methods and attributes. Commonly we will do:

    obj.setTitle("Now Hear This!")

Most other things you can do with the content depend on its API. Read the code, or check out DocFinderTab

by J. Cameron Cooper last modified February 7, 2006 - 12:53
Contributors: J Cameron Cooper
All content is copyright Plone Foundation and the individual contributors.

May also want to reindex()

Posted by Edmund Moseley at September 1, 2006 - 19:37
After I set the title of my object, everything seemed to work except the title of my object showed up as "[...]" in both the navigation portlet and folder_contents.

To remedy this, include:
obj.reindexObject()

... after setting attributes.

An example of this approach

Posted by Marilen Corciovei at November 22, 2006 - 20:16
Here is an example inspired from this document: http://len.is-a-geek.org/work/cms/create-links-with-a-script

Tie-in

Posted by Duke at March 18, 2008 - 17:05
How do you 'tie-in' to the running Plone instance?

Is there some way this can be done from a Python script in a shell?

Tie-in

Posted by J. Cameron Cooper at March 19, 2008 - 14:28
This can happen in any place where one writes code; for an application, generally this means Product code or Python scripts.

One can get a Python console hooked up to a live Zope instance through "zopectl debug". The same technique can be used to run Python scripts: "zopectl run".

Creating an event

Posted by Frank Grellert at September 21, 2008 - 12:37
The way you described above works fine, but when I created an event that way, the title returns an '', although I reindexed the object with obj.reindexObject().
Frank

For any issues with the web site functionality, please file a ticket.

Please consult the policy on plone.org content if you want your content published on this site.

Servers and hosting by