问题
Synopsis
I'm developing a web application to learn Django (python 3.4 & Django 1.6.10). The web app has complex and often updated workflows. I decided to integrate the Django-Viewflow library (https://github.com/viewflow/viewflow/) as it seems to be a very convenient way to handle workflows and not incorporate the workflow logic with the application models.
In this case, I have created a workflow to collect authorship information and copyrights using the Django-Viewflow library. The workflow should be initiated each time an author is added to a book.
My Problem
The documentation offers step by step guidelines to integrate an end-to-end worklfow solution (frontend and backend). My problem is that I'm having hard time to control the workflow programmatically (specifically from the Book model).
Description of the application
I have a Book model (core model) with a many to many relationship to Authors.
myApp/models.py
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
The workflow components are:
myFlow/models.py
from viewflow.models import Process
class AuthorInvitation(process)
consent_confirmed = models.BooleanField(default=False)
signature = models.CharField(max_length=150)
myFlow/flows.py
from viewflow import flow
from viewflow.base import this, Flow
from viewflow.contrib import celery
from viewflow.views import StartProcessView, ProcessView
from . import models, tasks
class AuthorInvitationFlow(Flow):
process_cls = models.AuthorInvitation
start = flow.Start(StartProcessView) \
.Permission(auto_create=True) \
.Next(this.notify)
notify = celery.Job(tasks.send_authorship_request) \
.Next(this.approve)
approve = flow.View(ProcessView, fields=["confirmed","signature"]) \
.Permission(auto_create=True) \
.Next(this.check_approve)
check_approve = flow.If(cond=lambda p: p.confirmed) \
.OnTrue(this.send) \
.OnFalse(this.end)
send = celery.Job(tasks.send_authorship) \
.Next(this.end)
end = flow.End()
Question
How can you control the workflow process programmatically (activate, confirm steps, redo steps, cancel the process....)? I have tried to dig into the code of the library. It seems that the class activate
contains the right method but not sure how the whole should be orchestrated.
Thanks in advance!
回答1:
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.
回答2:
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)
回答3:
to start manually:
from viewflow import flow
from viewflow.base import this, Flow
from .models import CIE
from viewflow import frontend
from django.utils.decorators import method_decorator
@frontend.register
class CIE(Flow):
process_class = CIE
start = flow.StartFunction(this.create_flow).Next(this.end)
end = flow.End()
@method_decorator(flow.flow_start_func)
def create_flow(self, activation):
activation.prepare()
activation.done()
return activation
after that expose rpc:
from modernrpc.core import rpc_method
from flow.flows import CIE
@rpc_method
def start():
CIE.start.run()
来源:https://stackoverflow.com/questions/28734247/how-to-create-a-django-viewflow-process-programmatically