A flexible and extensible Django application for defining and managing dynamic workflows with custom steps, statuses, and CEL-based conditional transitions.
Django Steps is a reusable Django application that provides a robust workflow management system. It allows developers to define multi-step workflows with conditional transitions, custom step statuses, and support for essential workflow operations like pausing, resuming, and canceling.
The core idea is to provide a structured way to manage complex processes within a Django application, where a process is composed of several steps, and each step can have multiple statuses. The transitions between steps can be controlled by CEL (Common Expression Language) expressions, allowing for dynamic and flexible workflow logic.
- Dynamic Workflows: Define workflows with multiple steps and transitions.
- Conditional Transitions: Use CEL expressions to control the flow between steps.
- Custom Statuses: Define custom statuses for each step, such as "Pending," "Approved," or "Rejected."
- Workflow Operations: Pause, resume, and cancel workflow instances.
- Generic Association: Link workflows to any Django model using generic foreign keys.
- Service-Oriented: A dedicated service layer to interact with workflow instances.
The application is built around a few key models:
Workflow
: Represents a workflow definition, such as "Claim Processing" or "User Onboarding."WorkflowStep
: Represents a single step within a workflow, like "Submit Claim" or "Verify Documents."WorkflowStepStatus
: Defines a custom status for a step, such as "Pending Review" or "Approved."WorkflowTransition
: Defines the transition from one step to another, with an optional CEL condition.WorkflowInstance
: Represents a running instance of a workflow for a specific Django model.
First, you need to define a workflow, its steps, statuses, and transitions. This can be done in the Django admin or programmatically.
Here's an example of how you might define a simple "Claim Processing" workflow:
+----------------+ +----------------+ +------------------+
| Submit Claim |----->| Review Claim |----->| Approve/Reject |
+----------------+ +----------------+ +------------------+
(Initial Step) (Final Step)
-
Workflow: "Claim Processing"
-
Steps:
- "Submit Claim" (Initial Step)
- "Review Claim"
- "Approve/Reject" (Final Step)
-
Statuses:
- For "Submit Claim": "Submitted" (Completion Status)
- For "Review Claim": "Under Review" (Default), "Approved" (Completion), "Rejected" (Completion)
- For "Approve/Reject": "Approved" (Completion), "Rejected" (Completion)
-
Transitions:
- From "Submit Claim" to "Review Claim" (unconditional)
- From "Review Claim" to "Approve/Reject" (unconditional)
To start a workflow for a specific object (e.g., a Claim
model), you can use the start_workflow_instance
service function:
from django_steps.services import start_workflow_instance
from myapp.models import Claim
claim = Claim.objects.get(id=123)
workflow_instance = start_workflow_instance(
workflow_name="Claim Processing",
content_object=claim
)
As the object moves through the process, you can update the status of the current step. If the new status is a "completion status," the workflow will automatically transition to the next step.
from django_steps.services import update_workflow_step_status
# This will move the workflow to the "Review Claim" step
update_workflow_step_status(
workflow_instance=workflow_instance,
new_status_name="Submitted"
)
If a transition has a condition, you can provide context data for the CEL evaluation:
# Example of a conditional transition
# Condition: "claim.amount > 1000"
update_workflow_step_status(
workflow_instance=workflow_instance,
new_status_name="Approved",
context_data={"claim": {"amount": 1500}}
)
You can also pause, resume, or cancel a workflow instance:
from django_steps.services import (
set_workflow_on_hold,
resume_workflow_instance,
cancel_workflow_instance
)
# Pause the workflow
set_workflow_on_hold(workflow_instance)
# Resume the workflow
resume_workflow_instance(workflow_instance)
# Cancel the workflow
cancel_workflow_instance(workflow_instance)
This project uses pytest for testing. The test suite is structured as follows:
/tests/
- The main test directoryconftest.py
- Shared pytest fixturestest_models.py
- Tests for model functionality and validationtest_workflow_operations.py
- Tests for workflow instance operationstest_services.py
- Tests for service layer functionspytest.ini
- Pytest configuration
To run the tests, use:
pytest
Or to run a specific test file:
pytest tests/test_models.py
Documentation is available in the /docs/
directory.
cd docs
make html
Then open _build/html/index.html
in your browser.