Django Moderation and Workflow Tools Reviewed

I have a requirement where entries created by users needs to be approved or rejected. Now this seems to be a common trait you can add to a model and something that needn’t be custom developed, a good use case for django behaviours

I digged a bit deeper and found that there are generic workflow and moderation apps that I can utilise instead of reinventing the wheel

The tools

  • django-moderation – a reusable application for Django framework, that allows to moderate any model objects [204 Stars]
  • activflow – a generic, light-weight & extensible Workflow Engine for agile automation of Business Processes [343 Stars]
  • viewflow – Reusable workflow library [942 Stars]
  • SpiffWorkflow – A powerful workflow engine implemented in pure Python [539 Stars]
  • django-river – Django workflow library supports on the fly changes [322 Stars]
  • django-fsm – Django friendly finite state machine support [972 Stars]

Here is a list of the workflow packages compared on django-packages

The Requirements

I need to add a status to the models. Have users notified that they need to take an action. Set certain related models as not requiring an authorisation.

Supplying a rejection note if rejected.

Permissions where only certain people can approve / reject a record.

Moderation queue.

Django Moderation

Basically works by creating a moderation object first that only becomes visible as a real object once it has been approved. There is a built in way of approving object in the django-admin and it is relatively easy to set up.

It also send emails to the moderators.

After creating an object the object created is not available or visible, until it is approved or rejected. So if you have a get_absolute_url for the model, it will 404 after creation.

In the admin you go to the moderation tab and have a list of moderated objects that need approval or rejection. Objects created from superadmin can be auto approved.

The approval and rejection screen for the object.

The statuses available are Approved, Rejected and Pending. It stores the name and date it was approved. You can also see a history of approval and rejection if you set that to true in the settings.

The email is sent to the user creating the object but surprising to me it was only sent when the object was created from the admin side. Even when I extended from from moderation.forms import BaseModeratedObjectForm on the frontend an email was not sent.

Setting visible_until_rejected to True, doesn’t store the object in the original model in my case. It was not visible.


This is used to create a more generic work flow, where you can set the statuses and activity flow your self.

I started working on it and realised you can’t just install the package with pip as there is no pypi package.


Installs easily with pypi and uses python 3.

Annotating a class based view with @flow.flow_start_view to start the flow.

Tasks execution rights could be restricted by the django permission system. So per object permissions for example a user only allowed to approve users in a specific company will have to be managed manually.

flow.Handler is the task performed by synchronous call a python code.

It does a lot for you, but unfortunately I’ve gone with a different frontend framework for django django-bootstrap instead of django-material. Also I need a fine grained process of approval with views that I’ll have to build myself. Perhaps it has some helpers.

This is how the workflow looks on the admin side.

viewflow-admin-viewA process list consists of many tasks related to a single object.


Then each Task is the same as those represented in the of the example:



After looking at the defaults created with the demo app, the workflow tasks seem to add a bit of crap. In my case all I need to see is that a leave request was created with a status of initiated and after a manger reviews it whether it is accepted or rejected.


Django Finite State machine. I found this great gist (article) after bumping my head on a few of the options I’ve mentioned above. It seems to make it a bit simpler to control the state and transitions.

It was made by the developer on viewflow and seems to be the simpler version.

It prevents running a state change event twice as an activity of state change can only happen if the source state is a specified state.

It seems like it will work correctly my only concerns is the ability to provide a reason for approving or rejecting and permissions of who can do the approval on a certain object which means I may ned to use django-guardian.

It seems that using conditions to check whether the approver can in fact approve a given users leave request is the way to go instead of permissions. But there is built in permissions

You can even prevent direct state change with protected=True, which is great as that ensures that the method to change state is always run.

Important thing to note is that the state is not saved until you actually run

So far it is the simplest moderation or workflow (state machine) I have seen and I like it. The only downside is no reason is supplied.

To fix the description / comment /reason issue I added a merge request into django-fsm-log, which is a utility that logs state changes in django-fsm.