



django-viewflow documentation

### Navigation

* [django-viewflow documentation](index.html#document-index) »

django-viewflow[¶](#django-viewflow "Permalink to this headline")

=================================================================

Ad-hoc business process automation framework for Django.

The process logic defined with django-viewflow is concentrated in one

clearly defined flow. You can organize your views, background jobs,

user permission checking in a simple, intuitive django-friendly way.

Contents[¶](#contents "Permalink to this headline")

---------------------------------------------------

### Introduction[¶](#introduction "Permalink to this headline")

#### Installation[¶](#installation "Permalink to this headline")

django-viewflow requires Python 3.3 or greater and django 1.7:

```

pip install django-viewflow

```

And add it into INSTALLED\_APPS settings

```

INSTALLED\_APPS = (

     ...

     'viewflow',

     'viewflow.site'

)

```

### Core concepts[¶](#core-concepts "Permalink to this headline")

#### Flow and Flow Tasks[¶](#flow-and-flow-tasks "Permalink to this headline")

django-viewflow introduces Flow classes as the single place to configure

and setup task, dependenices, persistance, user rights checking and interface setup.

Each flow should be subclass of [`viewflow.base.Flow`](#viewflow.base.Flow "viewflow.base.Flow").

*class* `viewflow.base.``Flow`[¶](#viewflow.base.Flow "Permalink to this definition")

Base class for flow definition

| Parameters: | * **process\_cls** – Defines model class for Process

* **task\_cls** – Defines model class for Task

* **management\_form\_cls** – Defines form class for task state tracking over GET requests

* **lock\_impl** – Locking implementation for flow

 |

`urls`[¶](#viewflow.base.Flow.urls "Permalink to this definition")

Provides ready to include urlpatterns required for this flow

Each flow could contains several flow tasks. Flow task represents declaration

of what should be performed on this step, and what next steps should be activated.

Flow does not have specific declaration of task transitions, and all logic of task activation

belongs to the task itself. This makes Flow code close to well-known BPMN notation, and

helps to convert it to BPMN and vise versa.

Flow class should have at least one of [`viewflow.flow.Start`](index.html#viewflow.flow.Start "viewflow.flow.Start") task and at least one of

[`viewflow.flow.End`](index.html#viewflow.flow.End "viewflow.flow.End")

*class* `viewflow.flow.``Node`(*activation\_cls=None*, *\*\*kwargs*)[¶](#viewflow.flow.Node "Permalink to this definition")

Base class for flow task

| Parameters: | * **task\_type** – Human readable task type

* **activation\_cls** – Activation implementation specific for this node

 |

`activate`(*prev\_activation*, *token*)[¶](#viewflow.flow.Node.activate "Permalink to this definition")

Creates task activation

See [*Flow Tasks*](index.html#document-flow_tasks) documentation for list of all available tasks.

#### Activation[¶](#activation "Permalink to this headline")

*class* `viewflow.activation.``Activation`(*\*args*, *\*\*kwargs*)[¶](#viewflow.activation.Activation "Permalink to this definition")

Base class for flow task activations.

Activation responsible for flow task state management and persistance

Each activation status chages restricted by a simple finite state automata

Base class enshures that all tasks could be undone or cancelled.

*classmethod* `activate`(*flow\_task*, *prev\_activation*, *token*)[¶](#viewflow.activation.Activation.activate "Permalink to this definition")

Instantiate and persist new flow task.

#### Models[¶](#models "Permalink to this headline")

django-viewflow provides base model for tracking the process state. In most cases you should

subclass [`viewflow.models.Process`](#viewflow.models.Process "viewflow.models.Process") to add additional data fields.

In case if you need to track some execution info or add logging, you can do it by

extending [`viewflow.models.Task`](#viewflow.models.Task "viewflow.models.Task")

*class* `viewflow.models.``Task`(*id*, *flow\_task*, *flow\_task\_type*, *status*, *created*, *started*, *finished*, *token*, *process*, *owner*, *external\_task\_id*, *owner\_permission*, *comments*)[¶](#viewflow.models.Task "Permalink to this definition")

*class* `viewflow.models.``Process`(*id*, *flow\_cls*, *status*, *created*, *finished*)[¶](#viewflow.models.Process "Permalink to this definition")

#### Views[¶](#views "Permalink to this headline")

#### Urls[¶](#urls "Permalink to this headline")

[`viewflow.base.Flow`](#viewflow.base.Flow "viewflow.base.Flow") collects all urls required by View tasks, you just

have to include it in urlpatters

```

urlpatterns = patterns('',

      url(r'^myflow/', include(MyFlow.instance.urls)))

```

### Flow tasks[¶](#flow-tasks "Permalink to this headline")

#### Start[¶](#start "Permalink to this headline")

*class* `viewflow.flow.``Start`(*\*args*, *\*\*kwargs*)[¶](#viewflow.flow.Start "Permalink to this definition")

Start process event

Example:

```

start = flow.Start(StartView, fields=["some\_process\_field"]) \

    .Available(lambda user: user.is\_super\_user) \

    .Activate(this.first\_start)

```

In case of function based view:

```

start = flow.Start(start\_process)

@flow\_start\_view()

def start\_process(request, activation):

     if not activation.has\_perm(request.user):

         raise PermissionDenied

     activation.prepare(request.POST or None)

     form = SomeForm(request.POST or None)

     if form.is\_valid():

          form.save()

          activation.done()

          return redirect('/')

     return render(request, {'activation': activation, 'form': form})

```

Ensure to include {{ activation.management\_form }} inside template, to proper

track when task was started and other task performance statistics:

```

<form method="POST">

     {{ form }}

     {{ activation.management_form }}

     <button type="submit"/>

</form>

```

`Available`(*owner=None*, *\*\*owner\_kwargs*)[¶](#viewflow.flow.Start.Available "Permalink to this definition")

Make process start action available for the User

accepts user lookup kwargs or callable predicate :: User -> bool:

```

.Available(username='employee')

.Available(lambda user: user.is_super_user)

```

`Permission`(*permission=None*, *auto\_create=False*, *obj=None*, *help\_text=None*)[¶](#viewflow.flow.Start.Permission "Permalink to this definition")

Make task available for users with specific permission,

aceps permissions name of callable :: Process -> permission\_name:

```

.Permission('my_app.can_approve')

.Permission(lambda process: 'my_app.department_manager_{}'.format(process.depratment.pk))

```

Task specific permission could be auto created during migration:

```

# Creates `processcls\_app.can\_do\_task\_processcls` permission

do\_task = View().Permission(auto\_create=True)

# You can specify permission codename and description right here

# The following creates `processcls\_app.can\_execure\_task` permission

do\_task = View().Permission('can\_execute\_task', help\_text='Custom text', auto\_create=True)

```

#### View[¶](#view "Permalink to this headline")

View task represents user task performed by interaction with django view.

*class* `viewflow.flow.``View`(*\*args*, *\*\*kwargs*)[¶](#viewflow.flow.View "Permalink to this definition")

View task

Example:

```

task = flow.View(some\_view) \

    .Permission('my\_app.can\_do\_task') \

    .Next(this.next\_task)

```

In case of function based view:

```

task = flow.Task(task)

@flow\_start\_view()

def task(request, activation):

     if not activation.flow\_task.has\_perm(request.user):

         raise PermissionDenied

     activation.prepare(request.POST or None)

     form = SomeForm(request.POST or None)

     if form.is\_valid():

          form.save()

          activation.done()

          return redirect('/')

     return render(request, {'activation': activation, 'form': form})

```

Ensure to include {{ activation.management\_form }} inside template, to proper

track when task was started and other task performance statistics:

```

<form method="POST">

     {{ form }}

     {{ activation.management_form }}

     <button type="submit"/>

</form>

```

`Assign`(*owner=None*, *\*\*owner\_kwargs*)[¶](#viewflow.flow.View.Assign "Permalink to this definition")

Assign task to the User immediately on activation,

accepts user lookup kwargs or callable :: Process -> User:

```

.Assign(username='employee')

.Assign(lambda process: process.created_by)

```

`Permission`(*permission=None*, *auto\_create=False*, *obj=None*, *help\_text=None*)[¶](#viewflow.flow.View.Permission "Permalink to this definition")

Make task available for users with specific permission,

aceps permissions name of callable :: Process -> permission\_name:

```

.Permission('my_app.can_approve')

.Permission(lambda process: 'my_app.department_manager_{}'.format(process.depratment.pk))

```

Task specific permission could be auto created during migration:

```

# Creates `processcls\_app.can\_do\_task\_processcls` permission

do\_task = View().Permission(auto\_create=True)

# You can specify permission codename and description right here

# The following creates `processcls\_app.can\_execure\_task` permission

do\_task = View().Permission('can\_execute\_task', help\_text='Custom text', auto\_create=True)

```

`viewflow.flow.``flow_view`(*\*\*lock\_args*)[¶](#viewflow.flow.flow_view "Permalink to this definition")

Decorator that locks and runs the flow view in transaction.

Expects view with the signature (request, activation, \*\*kwargs)

or CBV view that implements TaskActivation, in this case, dispatch

with would be called with (request, \*\*kwargs)

Returns (request, flow\_task, process\_pk, task\_pk, \*\*kwargs)

Views decorated with flow\_view decorator executed in transaction. If an error happens in view or

during nexttask activation, database rollback will be performed and no changes will be stored.

#### Job[¶](#job "Permalink to this headline")

Job task represents user task performed in background by celery

`viewflow.flow.``flow_job`(*\*\*lock\_args*)[¶](#viewflow.flow.flow_job "Permalink to this definition")

Decorator that prepares celery task for execution

Makes celery job function with the following signature

(flow\_task-strref, process\_pk, task\_pk, \*\*kwargs)

Expects actual celery job function which has the following signature (activation, \*\*kwargs)

If celery task class implements activation interface, job function is

called without activation instance (\*\*kwargs)

Process instance is locked only before and after the function execution.

Please avoid any process state modification during the celery job.

If any error will happens during job execution task would be moved to error state, and available

for administrator desision in admin interface. If error will happens on next task ativation, for

example, error raised on If conditions, job task will be commited and marked as done, but the

failed for activation task would be created in error state.

#### If[¶](#if "Permalink to this headline")

*class* `viewflow.flow.``If`(*cond*)[¶](#viewflow.flow.If "Permalink to this definition")

Activates one of paths based on condition

Example:

```

check\_decision = flow.If(lambda p: p.approved) \

    .OnTrue(this.approved) \

    .OnFalse(this.end)

```

#### Switch[¶](#switch "Permalink to this headline")

*class* `viewflow.flow.``Switch`[¶](#viewflow.flow.Switch "Permalink to this definition")

Activates first path with matched condition

#### Split[¶](#split "Permalink to this headline")

*class* `viewflow.flow.``Split`[¶](#viewflow.flow.Split "Permalink to this definition")

Activates outgoing path in-parallel depends on per-path condition.

Example:

```

split\_on\_decision = flow.Split() \

    .Next(check\_post, cond=lambda p: p,is\_check\_post\_required) \

    .Next(this.perform\_task\_always)

```

#### Join[¶](#join "Permalink to this headline")

*class* `viewflow.flow.``Join`(*wait\_all=True*)[¶](#viewflow.flow.Join "Permalink to this definition")

Waits for one or all incoming links and activates next path.

Join should be connected to one split task only

Example:

```

join\_on\_warehouse = self.Join() \

    .Next(this.next\_task)

```

#### End[¶](#end "Permalink to this headline")

*class* `viewflow.flow.``End`[¶](#viewflow.flow.End "Permalink to this definition")

Ends process event.

### Locking[¶](#locking "Permalink to this headline")

To avoid raise conditions on update [`viewflow.flow.flow\_view()`](index.html#viewflow.flow.flow_view "viewflow.flow.flow_view") and

[`viewflow.flow.flow\_job()`](index.html#viewflow.flow.flow_job "viewflow.flow.flow_job") decoratos grabs process-instance wide

locks and instansiate database transaction.

You could specify selected lock implementation in :attr:lock\_impl of

[`viewflow.base.Flow`](index.html#viewflow.base.Flow "viewflow.base.Flow") class

`viewflow.lock.``no_lock`(*flow*)[¶](#viewflow.lock.no_lock "Permalink to this definition")

No pessimistic locking, just execute flow task in transaction.

Not suitable when you have Join nodes in your flow.

`viewflow.lock.``select_for_update_lock`(*flow*, *nowait=True*, *attempts=5*)[¶](#viewflow.lock.select_for_update_lock "Permalink to this definition")

Uses select ... for update on process instance row for locking,

bound to database transaction.

Recommended for use with PostgreSQL.

`viewflow.lock.``cache_lock`(*flow*, *attempts=5*, *expires=120*)[¶](#viewflow.lock.cache_lock "Permalink to this definition")

Use it if primary cache backend has transactional add functionality,

like memcached.

### Administration[¶](#administration "Permalink to this headline")

*class* `viewflow.admin.``ProcessAdmin`(*model*, *admin\_site*)[¶](#viewflow.admin.ProcessAdmin "Permalink to this definition")

List all of viewflow process

*class* `viewflow.admin.``TaskAdmin`(*model*, *admin\_site*)[¶](#viewflow.admin.TaskAdmin "Permalink to this definition")

List all of viewflow tasks

### Examples[¶](#examples "Permalink to this headline")

#### Hello, world[¶](#hello-world "Permalink to this headline")

This example demostrate basic flow construction

#### Shipment[¶](#shipment "Permalink to this headline")

Standard BPMN example Shipment Process automated in hundred lines

License[¶](#license "Permalink to this headline")

-------------------------------------------------

[The GNU Affero General Public License v3.0](http://www.gnu.org/licenses/agpl-3.0.html)

### [Table Of Contents](index.html#document-index)

* [Introduction](index.html#document-introduction)

	+ [Installation](index.html#installation)

* [Core concepts](index.html#document-core_concepts)

	+ [Flow and Flow Tasks](index.html#flow-and-flow-tasks)

	+ [Activation](index.html#activation)

	+ [Models](index.html#models)

	+ [Views](index.html#views)

	+ [Urls](index.html#urls)

* [Flow tasks](index.html#document-flow_tasks)

	+ [Start](index.html#start)

	+ [View](index.html#view)

	+ [Job](index.html#job)

	+ [If](index.html#if)

	+ [Switch](index.html#switch)

	+ [Split](index.html#split)

	+ [Join](index.html#join)

	+ [End](index.html#end)

* [Locking](index.html#document-locking)

* [Administration](index.html#document-administration)

* [Examples](index.html#document-examples)

	+ [Hello, world](index.html#hello-world)

	+ [Shipment](index.html#shipment)

### Quick search

 Enter search terms or a module, class or function name.

 

### Navigation

* [django-viewflow documentation](index.html#document-index) »

 © Copyright 2014, Mikhail Podgurskiy.

 Created using [Sphinx](http://sphinx-doc.org/) 1.3.1.

 

