How to create a django ViewFlow process programmatically
I needed to be able to manually or programmatically start a flow instance. The model I ended up with, based on the above reference to StartFunction
looks like this:
class MyRunFlow(flow.Flow):
process_class = Run
start = flow.Start(ProcessCreate, fields=['schedule']). \
Permission(auto_create=True). \
Next(this.wait_data_collect_start)
start2 = flow.StartFunction(process_create). \
Next(this.wait_data_collect_start)
Note the important point is that process_create
has the Process
object and this code must programmatically set up the same fields that the manual form submission does via the fields specification to ProcessCreate
:
@flow_start_func
def process_create(activation: FuncActivation, **kwargs):
#
# Update the database record.
#
db_sch = Schedule.objects.get(id=kwargs['schedule'])
activation.process.schedule = db_sch # <<<< Same fields as ProcessCreate
activation.process.save()
#
# Go!
#
activation.prepare()
activation.done()
return activation
Note that the activation
subclass inside the flow_start_func
is FuncActivation
, which has the prepare() and save() methods. The kwargs
come from the call to run, which goes something like:
start_node = <walk the flow class looking for nodes of type StartFunction>
activation = start_node.run(schedule=self.id)
There are two additional Start build-in Tasks available for Flows
StartFunction - starts flow when the function called somewhere:
@flow_start_func
def create_flow(activation, **kwargs):
activation.prepare()
activation.done()
return activation
class FunctionFlow(Flow):
start = flow.StartFunction(create_flow) \
.Next(this.end)
# somewhere in the code
FunctionFlow.start.run(**some_kwargs)
StartSignal - starts flow on django signal receive:
class SignalFlow(Flow):
start = flow.StartSignal(some_signal, create_flow) \
.Next(this.end)
You can check the usage for them, and rest of build-in task in this viewflow test suite.
For manually process the task state, first you should get the task from the database, activate it, and call any activation method.
task = MyFlow.task_cls.objects.get(...)
activation = task.activate()
if activation.undo.can_proceed():
activation.undo()
Any activation transition have .can_proceed()
method, helps you to check, is the task in the state that allows the transition.