Trying out a very simple test app with viewflow.io using function based views rather than the built-in class based views. The intended idea is that a product is added and then approved (via two different views/ forms). There are two issues I cannot seem to work out:
Product
to the approval view (so that the user doing the approval can see the summary of what they are meant to approve. I am not sure how to do this - I tried passing the product_pk
via the flow.View
in flows.py
but this results in an error and if I leave it out then the approval view updates all records rather than the current product.flow.If
gate in flows.py always seems to be True regardless of whether the approved field in Product has been check or not. Ideally I am hoping that the approval is recorded in the Product model rather than the process modelProbably super basic mistake/ concept I am missing - any help would be appreciated.
In models.py
class Product(models.Model):
name = models.CharField(max_length=30)
quantity = models.IntegerField()
approved = models.BooleanField(default=False)
def __str__(self):
return self.name
class ProductProcess(Process):
product = models.ForeignKey(Product, blank=True, null=True)
def approved(self):
return self.product.approved
class ProductTask(Task):
class Meta:
proxy = True
In flows.py
class ProductFlow(Flow):
process_cls = ProductProcess
task_cls = ProductTask
start = flow.Start(start_process).Next(this.approve)
approve = flow.View(approve_product).Next(this.checkapproval)
checkapproval = flow.If(cond=lambda p: p.approved()) \
.OnFalse(this.approve) \
.OnTrue(this.end)
end = flow.End()
In views.py
@flow_start_view()
def start_process(request, activation):
activation.prepare(request.POST or None,)
form = ProductForm(request.POST or None)
if form.is_valid():
Product.objects.create(
name = form.cleaned_data['name'],
quantity = form.cleaned_data['quantity']
)
activation.done()
return redirect('/test')
return render(request, 'viewflowtest/product.html', {'activation': activation, 'form': form})
@flow_view()
def approve_product(request, activation):
activation.prepare(request.POST or None,)
form = ApproveProductForm(request.POST or None)
if form.is_valid():
Product.objects.update(
approved = form.cleaned_data['approved']
)
activation.done()
return redirect('/test')
return render(request, 'viewflowtest/product.html', {'activation': activation, 'form': form})
The form that is called is a very basic ModelForm class and the URLs are exactly as is described in the demo applications on the project GitHub pages. The template has the {{ activation.management_form }}
tag.
First of all, you need to link the product and process. So in start view, you can do
if form.is_valid():
product = Product.objects.create(
name = form.cleaned_data['name'],
quantity = form.cleaned_data['quantity']
)
activation.process.product = product
activation.done()
or even better, if the ProductForm is the ModelForm
if form.is_valid():
product = form.save()
activation.process.product = product
activation.done() # here is new process instance created and saved to db
So the approval view could be rewritten as::
@flow_view()
def approve_product(request, activation):
activation.prepare(request.POST or None,)
form = ApproveProductForm(request.POST or None, instance=activation.process.product)
if form.is_valid():
form.save() # here is the approved field is updated
activation.done()
return redirect('/test')
return render(request, 'viewflowtest/product.html', {'activation': activation, 'form': form})
In addition, you can take a look to the viewflow example with the function-based views - https://github.com/viewflow/cookbook/blob/master/viewflow_customization/customization/parcel/views.py