3.6. Defining a Workflow#
3.6.1. General#
A workflow describes how certain entities have to evolve between different states. Hence we have a set of states, and a âtransition graphâ, i.e. a set of possible transitions from one state to another state.
We will define a simple workflow for a blog, with only the following two states: submitted and published. You may want to take a look at Building a simple blog with CubicWeb if you want to quickly setup an instance running a blog.
3.6.2. Setting up a workflow#
We want to create a workflow to control the quality of the BlogEntry submitted on the instance. When a BlogEntry is created by a user its state should be submitted. To be visible to all, it has to be in the state published. To move it from submitted to published, we need a transition that we can call approve_blogentry.
A BlogEntry state should not be modifiable by every user. So we have to define a group of users, moderators, and this group will have appropriate permissions to publish a BlogEntry.
There are two ways to create a workflow: from the user interface, or
by defining it in migration/postcreate.py
. This script is executed
each time a new cubicweb-ctl db-init
is done. We strongly
recommend to create the workflow in migration/postcreate.py
and we
will now show you how. Read Two bits of warning to understand why.
The state of an entity is managed by the in_state attribute which can be added to your entity schema by inheriting from cubicweb.schema.WorkflowableEntityType.
About our example of BlogEntry, we must have:
from cubicweb.schema import WorkflowableEntityType
class BlogEntry(WorkflowableEntityType):
...
3.6.2.1. Creating states, transitions and group permissions#
The postcreate
script is executed in a special environment,
adding several CubicWeb primitives that can be used.
They are all defined in the ServerMigrationHelper
class.
We will only discuss the methods we use to create a workflow in this example.
A workflow is a collection of entities of type State
and of type
Transition
which are standard CubicWeb entity types.
To define a workflow for BlogDemo, please add the following lines
to migration/postcreate.py
:
from cubicweb import _
moderators = add_entity('CWGroup', name=u"moderators")
This adds the moderators user group.
wf = add_workflow(u'blog publication workflow', 'BlogEntry')
At first, instanciate a new workflow object with a gentle description and the concerned entity types (this one can be a tuple for multiple value).
submitted = wf.add_state(_('submitted'), initial=True)
published = wf.add_state(_('published'))
This will create two entities of type State
, one with name
âsubmittedâ, and the other with name âpublishedâ.
add_state
expects as first argument the name of the state you want
to create and an optional argument to say if it is supposed to be the
initial state of the entity type.
wf.add_transition(_('approve_blogentry'), (submitted,), published, ('moderators', 'managers'),)
This will create an entity of type Transition
with name
approve_blogentry which will be linked to the State
entities
created before.
add_transition
expects
as the first argument: the name of the transition
then the list of states on which the transition can be triggered,
the target state of the transition,
and the permissions (e.g. a list of user groups who can apply the transition; the user has to belong to at least one of the listed group to perform the action).
Note
Do not forget to add the _() in front of all states and transitions names while creating a workflow so that they will be identified by the i18n catalog scripts.
In addition to the user groups (one of which the user needs to belong to), we could have added a RQL condition. In this case, the user can only perform the action if the two conditions are satisfied.
If we use an RQL condition on a transition, we can use the following variables:
X, the entity on which we may pass the transition
U, the user executing that may pass the transition
Itâs also possible to get a given transition (usefull in migration) from a workflow use transition_by_name(trname). To update the permission associated to the transition use set_permissions(requiredgroups=(), conditions=(), reset=True). If reset is False, then the new permission are added instead of replacing the old one.

You can notice that in the action box of a BlogEntry, the state is now listed as well as the possible transitions for the current state defined by the workflow.
The transitions will only be displayed for users having the right permissions. In our example, the transition approve_blogentry will only be displayed for the users belonging to the group moderators or managers.
3.6.2.2. Two bits of warning#
We could perfectly use the administration interface to do these operations. It is a convenient thing to do at times (when doing development, to quick-check things). But it is not recommended beyond that because it is a bit complicated to do it right and it will be only local to your instance (or, said a bit differently, such a workflow only exists in an instance database). Furthermore, you cannot write unit tests against deployed instances, and experience shows it is mandatory to have tests for any mildly complicated workflow setup.
Indeed, if you create the states and transitions through the user interface, next time you initialize the database you will have to re-create all the workflow entities. The user interface should only be a reference for you to view the states and transitions, but is not the appropriate interface to define your application workflow.
3.6.3. Alternative way to declare workflows#
Workflow setup utilities.
These functions work with a declarative workflow definition:
{
'etypes': 'CWGroup',
'default': True,
'initial_state': u'draft',
'states': [u'draft', u'published'],
'transitions': {
u'publish': {
'fromstates': u'draft',
'tostate': u'published',
'requiredgroups': u'managers'
'conditions': (
'U in_group X',
'X owned_by U'
)
}
}
}
- cubicweb.wfutils.setup_workflow(cnx, name, wfdef, cleanup=True)[source]#
Create or update a workflow definition so it matches the given definition.
- Parameters
cnx â A connexion with enough permissions to define a workflow
name â The workflow name. Used to create the Workflow entity, or to find an existing one.
wfdef â A workflow definition.
cleanup â Remove extra states and transitions. Can be done separatly by calling
cleanupworkflow()
.
- Returns
The created/updated workflow entity
- cubicweb.wfutils.cleanupworkflow(cnx, wf, wfdef)[source]#
Cleanup an existing workflow by removing the states and transitions that do not exist in the given definition.
- Parameters
cnx â A connexion with enough permissions to define a workflow
wf â A Workflow entity
wfdef â A workflow definition