### Install Django Viewflow PRO Source: https://docs.viewflow.io/overview/quick_start.html Installs the PRO version of Django Viewflow, requiring a license ID for the private index. ```bash pip install django-viewflow-pro --extra-index-url https://pypi.viewflow.io//simple/ ``` -------------------------------- ### Define a Sample Flow with Nodes Source: https://docs.viewflow.io/workflow/core_concepts.html This snippet demonstrates how to define a basic Viewflow Flow class with different types of nodes: Start, Handler, If (gateway), and End. It shows how nodes connect using `this` for forward references and includes example methods for performing tasks and checking conditions. ```python from viewflow import this from viewflow.workflow import flow, lock, act from viewflow.workflow.flow import views class SampleFlow(flow.Flow): start = flow.Start(my_view).Next(this.task) task = flow.Handler(perform_task).Next(this.check_status) check_status = flow.If(this.is_completed).Then(this.end).Else(this.task) end = flow.End() def perform_task(self, activation): activation.process.completed = random.randint(0, 1) def is_completed(self, activation): return activation.process.completed ``` -------------------------------- ### Run Django Migrations and Server Source: https://docs.viewflow.io/workflow/quick_start.html Apply database migrations for the 'helloworld' app and start the Django development server to run the workflow. ```bash ./manage.py makemigrations helloworld ./manage.py migrate ./manage.py runserver ``` -------------------------------- ### Start Flow Interactively with CreateArtifactView Source: https://docs.viewflow.io/workflow/writing.html Use flow.Start with CreateArtifactView to allow users to fill a form to start a flow and create a business object. ```python from viewflow import this from viewflow.workflow import flow from viewflow.workflow.flow import views class MyFlow(flow.Flow): start_with_artifact = ( flow.Start(views.CreateArtifactView.as_view(model=MyModel, fields=['message'])) .Annotation(title=_("Fill a form to start flow")) .Permission("myapp.can_start_request") .Next(this.next_task) ) ``` -------------------------------- ### Base Page Template Example Source: https://docs.viewflow.io/crud/templates.html Example of extending the base template for application-specific pages, used for global drawer appearance. ```html {% extends 'viewflow/base_page.html' %} TODO: Sample... ``` -------------------------------- ### Create Virtual Environment and Activate Source: https://docs.viewflow.io/overview/quick_start.html Sets up an isolated Python environment for the project and activates it. Ensure Python 3.8+ and Django 4.0+ are installed. ```bash python3 -m venv .venv source .venv/bin/activate ``` -------------------------------- ### Install Django Viewflow Source: https://docs.viewflow.io/overview/quick_start.html Installs the open-source version of the Django Viewflow package using pip. ```bash pip install django-viewflow ``` -------------------------------- ### Start Flow Programmatically with StartHandle Source: https://docs.viewflow.io/workflow/writing.html Use flow.StartHandle to initiate flows from your code, optionally passing initial data. ```python from viewflow import this from viewflow.workflow import flow class MyFlow(flow.Flow): start_noninteractive = flow.StartHandle(this.start_process).Next(this.approve) def start_process(self, activation, message=''): object = MyModel.objects.create(message=message) activation.process.artifact = object return activation.process # Start from anywhere in your code process = MyFlow.start_noninteractive.run(message="Hello World") ``` -------------------------------- ### Example FSM in DOT Format Source: https://docs.viewflow.io/fsm/visualization.html An example of a document review FSM represented in DOT format, showing states and transitions. This is the raw output format before rendering. ```dot digraph { graph [rankdir=TB, size="8,8"]; node [shape=box, style="filled", fillcolor="#f5f5f5", fontsize=10]; edge [fontsize=9]; NEW [label="NEW", fillcolor="#e1f5fe"]; UNDER_REVIEW [label="UNDER REVIEW"]; APPROVED [label="APPROVED"]; REJECTED [label="REJECTED"]; PUBLISHED [label="PUBLISHED", fillcolor="#e8f5e9"]; NEW -> UNDER_REVIEW [label="submit"]; UNDER_REVIEW -> APPROVED [label="approve"]; UNDER_REVIEW -> REJECTED [label="reject"]; APPROVED -> PUBLISHED [label="publish"]; REJECTED -> NEW [label="revise"]; } ``` -------------------------------- ### Main Flow with NSubprocess Source: https://docs.viewflow.io/workflow/nodes.html Demonstrates the use of NSubprocess to start multiple instances of a subprocess. Each instance is initiated with a different item from a provided list. ```python class MainFlowWithNSubprocess(flow.Flow): start = flow.StartFunction().Next(this.nsubprocess) nsubprocess = flow.NSubprocess(ExampleSubFlow.start, lambda p: [1, 2, 3, 4]).Next(this.end) end = flow.End() ``` -------------------------------- ### Install Dash Dependency Source: https://docs.viewflow.io/dashboard/index.html Ensure Dash is installed as a required dependency for creating dashboards. Run this command in your terminal. ```bash pip install dash ``` -------------------------------- ### Example Subprocess Flow Source: https://docs.viewflow.io/workflow/nodes.html Defines a simple subprocess flow with start, task, and end points. Used to illustrate subprocess integration. ```python class ExampleSubFlow(flow.Flow): start = flow.StartHandle(this.start_func).Next(this.task) task = flow.Handle(this.task_func).Next(this.end) end = flow.End() def start_func(self, activation, item=0): # instantialed with one of 1, 2, 3, 4 as item activation.process.data = item def task_func(self, activation): activation.process.data += 100 ``` -------------------------------- ### Starting a Flow with a Form Source: https://docs.viewflow.io/workflow/data_flow.html Initiate a Viewflow process by specifying a form class for creating the initial process instance. ```python class SampleFlow(flow.Flow): start = flow.Start( CreateProcessView.as_view( form_class=SelectSourceForm, ), ).Next(...) ``` -------------------------------- ### Basic Site and Application Structure Source: https://docs.viewflow.io/crud/site.html Defines a site with applications and viewsets, and sets up URL patterns for authentication and the site itself. This is a foundational setup for organizing your application's structure. ```python from viewflow.contrib.auth import AuthViewset from viewflow.urls import Site, Application site = Site(title="Workforce management", viewsets=[ Application( title='Employees', icon=Icon('people'), app_name='emp', viewsets=[ EmployeeViewset(), DepartmentViewset(), ), ]) urlpatterns = [ path('accounts/', AuthViewset().urls), path('', site.urls), ] ``` -------------------------------- ### Run Django Development Server Source: https://docs.viewflow.io/overview/quick_start.html Starts the Django development server, making the application accessible at http://127.0.0.1:8000. ```bash ./manage.py runserver ``` -------------------------------- ### Start Node Configuration Source: https://docs.viewflow.io/workflow/nodes.html Defines the initial step of a flow, typically for user interaction. It can be configured with a view, annotations, permissions, and the next node in the sequence. ```python class MyFlow(flow.Flow): start = ( flow.Start(views.CreateProcessView.as_view(fields=["text"])) .Annotation(title=_("New message")) .Permission(auto_create=True) .Next(this.approve) ) ... ``` -------------------------------- ### Custom Process Data Template Example Source: https://docs.viewflow.io/workflow/templates.html Example of customizing the process data view by creating a custom template at the flow-specific level. ```django {# myapp/myapp/process_data.html #}

Process Information

{{ process.pk }}
{{ process.created|date:"F j, Y, H:i" }}
{{ process.get_status_display }}
{% if process.artifact %}
View Details
{% endif %}
``` -------------------------------- ### Start Node Availability Source: https://docs.viewflow.io/workflow/nodes.html Specifies which users can initiate a flow. This can be based on username or a callable predicate that returns a boolean. ```python .Available(username='employee') .Available(lambda user: user.is_super_user) ``` -------------------------------- ### Apply Migrations and Create Superuser Source: https://docs.viewflow.io/overview/quick_start.html Applies pending database migrations for installed Django apps and creates an administrator user account. ```bash ./manage.py migrate ./manage.py createsuperuser ``` -------------------------------- ### Start a New Django App Source: https://docs.viewflow.io/crud/quickstart.html Use the Django startapp command to create a new application. This command initializes the necessary files and structure for a new app within your Django project. ```bash python manage.py startapp atlas ``` -------------------------------- ### Complete Form Definition with Layout and FormSet Source: https://docs.viewflow.io/forms/layout.html A comprehensive example demonstrating a Django Form with nested FormSets and a custom layout. ```python class AddressForm(Form): line_1 = forms.CharField(max_length=250) line_2 = forms.CharField(max_length=250) state = forms.CharField(max_length=100) city = forms.CharField(max_length=100) zipcode = forms.CharField(max_length=10) layout = Layout( Caption("Address"), "line_1", "line_2", "state", Row("city", "zipcode"), ) AddressFormSet = forms.formset_factory(AddressForm, extra=3, can_delete=True) class SignupForm(Form): username = forms.CharField( max_length=50, widget=forms.TextInput(attrs={"leading-icon": "account_box"}), ) first_name = forms.CharField(max_length=250) last_name = forms.CharField(max_length=250) date_of_birth = forms.DateField() emails = FormSetField(formset_class=EmailFormSet) addresses = FormSetField(formset_class=AddressFormSet) layout = Layout( "username", Row("first_name", "last_name", "date_of_birth"), "emails", FormSet("addresses", card_desktop=4), ) ``` -------------------------------- ### Custom Task Detail Template Example Source: https://docs.viewflow.io/workflow/templates.html Example of customizing the task detail view by extending the base template and overriding the 'task_details' block. ```django {# myapp/myapp/approve_task_detail.html #} {% extends 'viewflow/workflow/task_detail.html' %} {% block task_details %}

{{ task.flow_task.task_title }}

{{ task.get_status_display }}

Created: {{ task.created|date:"F j, Y, H:i" }}

{% if task.owner %}

Assigned to: {{ task.owner.get_full_name|default:task.owner.username }}

{% endif %}
{% if task|can_execute:request.user %} Process Task {% endif %}
{% endblock %} ``` -------------------------------- ### Start Node Permissions Source: https://docs.viewflow.io/workflow/nodes.html Configures task availability based on user permissions. Permissions can be specified by name or dynamically generated using a callable. ```python .Permission('my_app.can_approve') .Permission(lambda process: 'my_app.department_manager_{}'.format(process.department.pk)) ``` -------------------------------- ### Install Vite as a Dev Dependency Source: https://docs.viewflow.io/crud/css_and_js.html Install Vite using npm to manage your JavaScript build process. This is a prerequisite for configuring Vite. ```bash npm init -y npm install vite --save-dev ``` -------------------------------- ### Custom Transition Action with Permissions and Validation Source: https://docs.viewflow.io/fsm/rest.html Implement custom actions for transitions, including permission checks and validation before proceeding. This example shows an 'approve' action. ```python @action(methods=['POST'], detail=True, url_path='transition/approve') def approve(self, request, *args, **kwargs): instance = self.get_object() flow = self.get_object_flow(request, instance) if not flow.approve.has_perm(request.user): raise PermissionDenied if not flow.approve.can_proceed(): raise ValidationError(_('Transition is not allowed')) serializer = self.get_serializer(instance, data=request.data, partial=True) serializer.is_valid(raise_exception=True) self.perform_update(serializer) flow.approve() return Response(serializer.data) ``` -------------------------------- ### Basic Authentication URL Configuration Source: https://docs.viewflow.io/contrib/auth.html Configure URL patterns for user authentication using AuthViewset. This example disables password change functionality. ```python urlpatterns = [ path('accounts/', AuthViewset( allow_password_change=False, login_view=views.LoginView.as_view( authentication_form=MyAuthForm ), ).urls), ] ``` -------------------------------- ### Configure URL Routing Source: https://docs.viewflow.io/workflow/quick_start.html Add the HelloWorldFlow to your URL configuration using FlowAppViewset to create URLs for starting processes, executing tasks, and viewing details. ```python from django.urls import path from viewflow.contrib.auth import AuthViewset from viewflow.urls import Application, Site, ModelViewset from viewflow.workflow.flow import FlowAppViewset from helloworld.flows import HelloWorldFlow site = Site(title="ACME Corp", viewsets=[ Application( title='Sample App', icon='people', app_name='sample', viewsets=[ FlowAppViewset(HelloWorldFlow, icon="assignment"), ] ), ]) urlpatterns = [ path('accounts/', AuthViewset(with_profile_view=False).urls), path('', site.urls), ] ``` -------------------------------- ### Django Admin Integration Setup Source: https://docs.viewflow.io/contrib/admin.html Set up the Django administration Viewset adapter for quick access to Django admin from your main website. This requires importing necessary modules and configuring the site URLs. ```python from django.contrib import admin from viewflow.contrib.admin import Admin site = Site(viewsets=[ Admin() ]) urls = [ path("admin/", admin.site.urls), path('', site.urls) ] ``` -------------------------------- ### Start multiple instances of a subprocess flow Source: https://docs.viewflow.io/workflow/nodes.html Use NSubprocess node to start multiple instances of a subprocess flow, each processing a different item. All subprocesses must complete before the parent flow proceeds. This feature is available in PRO versions. ```python class ExampleSubFlow(flow.Flow): start = flow.StartHandle(this.start_func).Next(this.task) task = flow.Handle(this.task_func).Next(this.end) end = flow.End() def start_func(self, activation, item=0): # instantialed with one of 1, 2, 3, 4 as item activation.process.data = item def task_func(self, activation): activation.process.data += 100 class MainFlowWithNSubprocess(flow.Flow): start = flow.StartFunction().Next(this.nsubprocess) nsubprocess = flow.NSubprocess(ExampleSubFlow.start, lambda p: [1, 2, 3, 4]).Next(this.end) end = flow.End() ``` -------------------------------- ### Timer Node Usage Source: https://docs.viewflow.io/workflow/nodes.html Example of using the Timer node to introduce a delay before proceeding to the next step in a workflow. Requires importing the celery module. ```python from viewflow.contrib import celery class MyFlow(Flow): ... wait = celery.Timer(timedelta(minutes=10)).Next(this.check) ...._ ``` -------------------------------- ### Execute OnCreate Task Event Source: https://docs.viewflow.io/workflow/nodes.html Defines a callback function to be executed when a task is created. This example shows how to send an email notification when a task is assigned. ```python class MyFlow(Flow): approve = flow.View(...).OnCreate(this.on_approve_created) def on_approve_created(self, activation): if activation.task.owner: send_mail( 'View task assigned to you','Here is the message.', 'from@example.com', [activation.task.owner.email] ) ``` -------------------------------- ### Define HelloWorldFlow Source: https://docs.viewflow.io/workflow/quick_start.html Map the BPMN diagram to Python code by defining nodes like start, approve, check_approve, send, and end using viewflow.workflow.flow classes. ```python from viewflow import this from viewflow.workflow import flow, lock, act from viewflow.workflow.flow import views from .models import HelloWorldProcess class HelloWorldFlow(flow.Flow): process_class = HelloWorldProcess start = ( flow.Start(views.CreateProcessView.as_view(fields=["text"])) .Annotation(title="New message") .Permission(auto_create=True) .Next(this.approve) ) approve = ( flow.View(views.UpdateProcessView.as_view(fields=["approved"])) .Permission(auto_create=True) .Next(this.check_approve) ) check_approve = ( flow.If(act.process.approved) .Then(this.send) .Else(this.end) ) send = ( flow.Function(this.send_hello_world_request) .Next(this.end) ) end = flow.End() def send_hello_world_request(self, activation): print(activation.process.text) ``` -------------------------------- ### Custom Transition Action Source: https://docs.viewflow.io/fsm/rest.html Provides an example of a custom transition action method (`approve`) within a ViewSet. This method handles permission checks, transition validation, object updates, and the actual flow transition execution. ```APIDOC ## Custom Transition Action: approve ### Description Handles the 'approve' transition action, including permission checks, validation, and execution. ### Method POST ### Endpoint `/your-endpoint/transition/approve` ### Parameters #### Path Parameters - **id** (int) - Required - The ID of the object to approve. #### Query Parameters None explicitly defined. #### Request Body - **(fields depend on serializer_class)** - Optional - Data for partial update. ### Request Example ```json { "example": "request body" } ``` ### Response #### Success Response (200) - **(fields depend on serializer_class)** - Description of the updated object after approval. #### Response Example ```json { "example": "response body" } ``` ``` -------------------------------- ### Customize Create and Update Forms Source: https://docs.viewflow.io/crud/crud.html Customize form layouts, classes, and widgets for create and update operations. This example shows setting a specific update form class and defining form widgets with dependent selections. ```python class ContinentViewset(ModelViewset): # ... other options ... create_form_layout = Layout( # Layout configuration for create form ) form_layout = Layout( # Layout configuration ) update_form_class = forms.ContinentForm form_widgets = { 'planet': DependentModelSelect( depends_on='galaxy', queryset=lambda galaxy: Planet.objects.filter(galaxy=galaxy) ) } ``` -------------------------------- ### Subprocess Node for Nested Workflows (PRO-only) Source: https://docs.viewflow.io/workflow/nodes.html The Subprocess node starts a nested workflow. The parent flow pauses until the subprocess is completed. This example shows how to define a main flow that includes a subprocess. ```python class ExampleSubFlow(flow.Flow): start = flow.StartHandle(this.start_func).Next(this.task) task = flow.Handle(this.task_func).Next(this.end) end = flow.End() def start_func(self, activation): # get access to parent process and data activation.process.parent_task.process.data def task_func(self, activation): pass class MainFlowWithSubprocess(flow.Flow): start = flow.StartHandle().Next(this.subprocess) ``` -------------------------------- ### Create Django Project and App Source: https://docs.viewflow.io/overview/quick_start.html Generates the basic structure for a Django project named 'demo' and an app named 'helloworld'. ```bash django-admin startproject demo . ./manage.py startapp helloworld ``` -------------------------------- ### Create Vite Project Structure Source: https://docs.viewflow.io/crud/css_and_js.html Prepare your project directory by creating the 'components' folder and an empty 'index.js' file within it. This structure is required by the Vite configuration. ```bash mkdir components/ touch components/index.js ``` -------------------------------- ### Defining a Basic Viewset Source: https://docs.viewflow.io/crud/viewset.html Demonstrates how to create a custom Viewset by inheriting from `viewflow.urls.Viewset` and defining URL paths as class attributes. ```python from django.urls import path from viewflow.urls import Viewset class WebsiteViewset(Viewset): index_path = path('', index_view, name='index') ``` -------------------------------- ### Inherit from ModelViewset Source: https://docs.viewflow.io/crud/crud.html Inherit from a viewset class to override methods and attributes for custom behavior. This example defines a DepartmentViewset. ```python class DepartmentViewset(ModelViewset): icon = Icon('people') model = models.Department list_columns = ('name', 'manager', 'parent') list_filter_fields = ('parent', ) ``` -------------------------------- ### Configure Django Settings for Viewflow Source: https://docs.viewflow.io/overview/quick_start.html Adds 'viewflow' and the custom app 'helloworld' to the INSTALLED_APPS list in the Django project's settings. ```python INSTALLED_APPS = [ ... 'viewflow', 'helloworld', ] ``` -------------------------------- ### Defining a URL Path as a Property Source: https://docs.viewflow.io/crud/viewset.html Illustrates how to define a URL path dynamically using a property, allowing for more complex logic or dynamic path generation. ```python @property def page_path(self): return path('page/', self.page_view, name='page')) def page_view(self, request): return render(request, 'page.html') ``` -------------------------------- ### reverse Source: https://docs.viewflow.io/workflow/viewsets.html Get the URL for a given viewname, including the namespace. This function is useful for dynamically generating URLs within your application. ```APIDOC ## reverse ### Description Get the URL for a given viewname, including the namespace. ### Method N/A (Python function) ### Parameters #### Path Parameters None #### Query Parameters None #### Keyword Arguments - **viewname** (str) - Required - The name of the view. - **args** (Optional[List[Any]]) - Optional - Positional arguments for the view. - **kwargs** (Optional[Dict[str, Any]]) - Optional - Keyword arguments for the view. - **current_app** (Optional[str]) - Optional - The current application namespace. ### Returns - **str** - The URL for the view with the appropriate namespace ``` -------------------------------- ### Task Permissions with Auto Creation Source: https://docs.viewflow.io/workflow/nodes.html Demonstrates how to define task-specific permissions that can be automatically created during migrations. This includes specifying codenames and help text. ```python # Creates `process_class.can_do_task_process_class` permission do_task = View().Permission(auto_create=True) # You can specify permission codename and description right here # The following creates `process_class.can_execute_task` permission do_task = View().Permission('can_execute_task', help_text='Custom text', auto_create=True) ``` -------------------------------- ### Restricting Site/Application Access Source: https://docs.viewflow.io/crud/site.html Implements a `has_perm` method to control access to a site or application. This example restricts access to users who are staff members. ```python def has_perm(request, user): return user.is_staff ``` -------------------------------- ### Layout with Column and Responsive Sizing Source: https://docs.viewflow.io/forms/layout.html Illustrates using Column to stack elements vertically and Span within a Row to control responsive sizing for different devices. ```python layout = Layout( Row( Column('first_name', 'last_name', desktop=8, tablet=6), 'sex_options' ) ) ``` -------------------------------- ### Handle State Transitions in Django Views Source: https://docs.viewflow.io/fsm/models.html Implement Django views to handle FSM transitions, including permission checks and form processing. ```python from django.shortcuts import get_object_or_404, redirect, render from django.core.exceptions import PermissionDenied from .models import Report from .forms import ApproveForm from .flow import ReportFlow def approve(request, report_pk): report = get_object_or_404(Report, pk=report_pk) flow = ReportFlow(report) if not flow.approve.has_perm(request.user): raise PermissionDenied form = ApproveForm(request.POST or None, instance=report) if form.is_valid(): form.save(commit=False) flow.approve() return redirect('../') return render(request, 'approve.html', { 'report': report, 'flow': flow, 'form': form }) ``` -------------------------------- ### Define a Django Model Source: https://docs.viewflow.io/crud/quickstart.html Define a new model in your app's models.py file. This example creates a 'City' model with 'name' and 'population' fields. ```python from django.db import models class City(models.Model): name = models.CharField(max_length=250) population = models.PositiveIntegerField() ``` -------------------------------- ### StartHandle Node Initialization Source: https://docs.viewflow.io/workflow/nodes.html Initializes a flow from code using a StartHandle node, which is linked to a callable function for process initiation. It also defines the next node and allows passing arguments. ```python class MyFlow(flow.Flow): start = flow.StartHandle(this.on_start_process).Next(this.approve) def start_process(self, activation, sample=False): activation.process.sample = sample return activation.process ... process = MyFlow.start.run(sample=True) ``` -------------------------------- ### Include Single Flow into URL Patterns Source: https://docs.viewflow.io/workflow/viewsets.html Use FlowViewset to include a single flow into your Django URL patterns. This is a basic setup for a standalone flow. ```python urlpatterns = [ path("my_flow/", FlowViewset(MyFlow).urls) ] ``` -------------------------------- ### Render Chart as PNG in Django View Source: https://docs.viewflow.io/fsm/visualization.html Converts the DOT graph to PNG format using pydot and returns it as an HTTP response. Ensure pydot is installed and configured. ```python import pydot from django.http import HttpResponse from viewflow.fsm import chart from .flow import ReportFlow def flow_chart_image(request): dot_graph = chart(ReportFlow.state_field) graphs = pydot.graph_from_dot_data(dot_graph) graph = graphs[0] png_data = graph.create_png() return HttpResponse(png_data, content_type='image/png') ``` -------------------------------- ### Set Up Django URLs with Viewflow Site and Auth Source: https://docs.viewflow.io/overview/quick_start.html Configures the main URL patterns for the Django project, integrating Viewflow's Site for application management and AuthViewset for authentication. ```python from django.urls import path from django.contrib.auth.models import User from viewflow.contrib.auth import AuthViewset from viewflow.urls import Application, Site, ModelViewset site = Site(title="ACME Corp", viewsets=[ Application( title='Sample App', icon='people', app_name='sample', viewsets=[ ModelViewset(model=User), ] ), ]) urlpatterns = [ path('accounts/', AuthViewset(with_profile_view=False).urls), path('', site.urls), ] ``` -------------------------------- ### Customize Queryset with select_related Source: https://docs.viewflow.io/crud/crud.html Customize the queryset for a viewset to optimize querying or restrict listed models. This example uses select_related for performance and overrides get_queryset for user-specific filtering. ```python class EmployeeViewset(DetailViewMixin, ModelViewset): model = models.Employee queryset = model._default_manager.select_related('department') def get_queryset(self, request): if not request.user.is_staff: return self.queryset.exclude(department__parent_isnull=True) return self.queryset ``` -------------------------------- ### Defining Editable Fields for Transitions Source: https://docs.viewflow.io/fsm/admin.html Specify which fields should be editable alongside transitions by overriding the get_transition_fields method. This example allows editing 'text' and 'comment' for the 'approve' transition. ```python def get_transition_fields(self, request, obj, slug): if slug == 'approve': return ['text', 'comment'] ``` -------------------------------- ### Embedding a Formset for Many-to-Many with InlineFormSetField and AjaxModelSelect Source: https://docs.viewflow.io/forms/formsets.html Configure InlineFormSetField for many-to-many relationships using a 'through' model. The example demonstrates using AjaxModelSelect for efficient, on-demand loading of related choices. ```python from django.contrib.auth.models import User, Group from django.forms.models import inlineformset_factory from viewflow.forms import ModelForm, InlineFormSetField, AjaxModelSelect GroupFormSet = inlineformset_factory( User, Group.user_set.through, fields=("group",), can_delete=False, extra=1, widgets={"group": AjaxModelSelect(lookups=["name__istartswith"])} ) class UserForm(ModelForm): groups = InlineFormSetField(formset_class=GroupFormSet) class Meta: model = User fields = ["username", "first_name", "last_name"] ``` -------------------------------- ### This Shortcut Source: https://docs.viewflow.io/workflow/api.html Helper for building forward references to class attributes and methods, allowing references before declaration. ```APIDOC ## Class This ### Description Helper for building forward references to class attributes and methods. ### Methods - **resolve(instance: object, this_ref: ThisObject | ThisMethod | Any)**: Resolve a forward reference on the given instance. Args: instance (object): The instance on which to resolve the reference. this_ref (Union[ThisObject, ThisMethod, Any]): The reference to resolve. Returns: Any: The resolved reference. Raises: AttributeError: If the reference cannot be resolved. ``` -------------------------------- ### Create Custom Permission with Codename and Description Source: https://docs.viewflow.io/workflow/nodes.html Allows specifying a custom codename and help text for a permission, providing more descriptive access control. The permission created is `process_class.can_execute_task`. ```python do_task = View().Permission('can_execute_task', help_text='Custom text', auto_create=True) ``` -------------------------------- ### Start a subprocess flow within a parent flow Source: https://docs.viewflow.io/workflow/nodes.html Use Subprocess node to initiate a subprocess flow. The parent flow pauses until the subprocess is completed. This feature is available in PRO versions. ```python class ExampleSubFlow(flow.Flow): start = flow.StartHandle(this.start_func).Next(this.task) task = flow.Handle(this.task_func).Next(this.end) end = flow.End() def start_func(self, activation): # get access to parent process and data activation.process.parent_task.process.data def task_func(self, activation): pass class MainFlowWithSubprocess(flow.Flow): start = flow.StartHandle().Next(this.subprocess) subprocess = flow.Subprocess(ExampleSubFlow.start).Next(this.end) end = flow.End() ``` -------------------------------- ### Nesting Viewsets Source: https://docs.viewflow.io/crud/viewset.html Explains how to nest one Viewset within another using the `route` function to create hierarchical URL structures. ```python from viewflow.urls import route, Viewset class UserViewset(Viewset): page_path = path('account/', self.account_view name="account") class WebsiteViewset(Viewset): users_path = route('auth/', UserViewset()) ``` -------------------------------- ### Define CompositeKey in Django Model Source: https://docs.viewflow.io/orm/composite_fk.html Example of defining a CompositeKey field in a Django model to access a database table with a composite foreign key. This field is virtual and intended for models where Meta.managed = False. ```python from viewflow.fields import CompositeKey class Seat(models.Model): id = CompositeKey(columns=['aircraft_code', 'seat_no']) aircraft_code = models.ForeignKey(Aircraft, models.DO_NOTHING) seat_no = models.CharField(max_length=4) class Meta: managed = False db_table = 'aircrafts_data' ``` -------------------------------- ### Context Variables for Process Detail Template Source: https://docs.viewflow.io/workflow/templates.html Provides context variables available within the process detail template. ```python { 'process': Process model instance, 'flow_class': The Flow class, 'tasks': QuerySet of Task instances } ``` -------------------------------- ### Custom Navigation Menu HTML Source: https://docs.viewflow.io/crud/site.html An example of a custom HTML template for an application's navigation menu. It uses Viewflow's template tags to render menu items for employees and departments. ```html {% load viewflow_site %}
``` -------------------------------- ### Reversing URLs with Namespaces Source: https://docs.viewflow.io/crud/viewset.html Demonstrates how to use Django's `reverse` function to generate URLs for views defined within Viewsets, considering default and nested namespaces. ```python from django.urls import reverse >>> reverse('website:index') '/' >>> reverse('website:page') '/page/' >>> reverse('website:user:account') '/auth/account/' ``` -------------------------------- ### Initializing Task Data Conditionally Source: https://docs.viewflow.io/workflow/data_flow.html Create a task with pre-initialized data based on a condition, using lambda functions to define the data. ```python # Create task with preinitialized data next_task = ( flow.If( cond=lambda activation: activation.task.seed.fresh ) .Then( this.plant, task_data=lambda activation: {'seed': activation.task.seed} ) .Else( this.eat, task_data=lambda activation: {'grain': activation.task.seed} ) ) ``` -------------------------------- ### Define FSM States and Transitions Source: https://docs.viewflow.io/fsm/index.html Demonstrates how to define states using an Enum and transitions using the @transition decorator. States cannot be assigned directly and must be changed via defined transitions. ```python from enum import Enum from viewflow.fsm import State class States(Enum): NEW = 1 DONE = 2 HIDDEN = 3 class MyFlow(object): state_field = State(States, default=States.NEW) @state_field.transition(source=States.NEW, target=States.DONE) def complete(): pass @state_field.transition(source=State.ANY, target=States.HIDDEN) def hide(): pass flow = MyFlow() flow.state_field == States.NEW # True flow.state_field = States.DONE # Raises AttributeError flow.complete() flow.state_field == States.DONE # True flow.complete() # Raises TransitionNotAllowed ``` -------------------------------- ### Enable Pessimistic Locking in Flow Source: https://docs.viewflow.io/workflow/core_concepts.html To enable pessimistic locking in Viewflow, specify the `lock_impl` attribute in your Flow class. This example uses `lock.select_for_update_lock` to acquire a database lock during view execution, preventing race conditions. ```python from viewflow.workflow import lock class SampleFlow(flow.Flow): lock_impl = lock.select_for_update_lock ``` -------------------------------- ### Site Branding with Colors Source: https://docs.viewflow.io/crud/site.html Sets primary and secondary colors for site branding. This allows for quick customization of the site's visual theme. ```python site = Site( title="Workforce management", primary_color='#3949ab', secondary_color='#5c6bc0', viewsets=[ EmployeeViewset(), DepartmentViewset(), ] ) ``` -------------------------------- ### Overriding a Custom Transition View Source: https://docs.viewflow.io/fsm/admin.html Completely replace a transition's view by defining custom URLs and view logic. This example shows how to override the 'reject' transition view, including permission checks and state updates. ```python def get_urls(self): return [path( '/transition/reject/', self.admin_site.admin_view(self.reject_view), )] + super().get_urls() def reject_view(self, request, object_id): obj = get_object_or_404(self.model, pk=object_id) flow = self.get_object_flow(request, obj) if not flow.reject.has_perm(request.user) or not flow.reject.can_proceed(): raise PermissionDenied if request.method == "POST": flow.reject() obj.save() return redirect('../../') return render(request, ...) ``` -------------------------------- ### Send Hello World Request Task Source: https://docs.viewflow.io/workflow/writing.html A Celery task to demonstrate background processing within a Viewflow activation. It updates a process field without using locks. ```python from celery import shared_task from viewflow.flow import flow_job @shared_task def send_hello_world_request(activation_ref): with Job.activate(activation_ref) as activation: result = 'Background Processing Done' # No locks during long jobs - save carefully activation.process.sample_text = result activation.process.save(updated_fields=['sample_text']) ``` -------------------------------- ### AJAX Autocomplete Request Handling Source: https://docs.viewflow.io/forms/widgets.html Illustrates how to handle an AJAX OPTIONS request for autocomplete suggestions, extracting query parameters. ```python if request.method == "OPTIONS" and "HTTP_X_REQUEST_AUTOCOMPLETE" in request.META: query = request.META.get("HTTP_X_REQUEST_AUTOCOMPLETE") options = QueryDict(query, encoding=self.request.encoding) field_name = options.get("field", "") query = options.get("query") ... ``` -------------------------------- ### Link Business Data using Generic Foreign Key Source: https://docs.viewflow.io/workflow/writing.html Store business data in separate models and link to them using the Process model's 'artifact' generic foreign key. ```python class MyModel(models.Model): message = models.CharField(max_length=150) def task_view(request, **kwargs): form = MyModelForm(request.POST or None) if form.is_valid(): object = form.save(commit=True) request.activation.process.artifact = object # additional code here.. ``` -------------------------------- ### Basic FSM Viewset Integration Source: https://docs.viewflow.io/fsm/viewset.html Integrates a Django model with a Flow class using FlowViewsMixin and ModelViewSet. Exposes transitions as detail actions. ```Python # viewset.py from viewflow.fsm import FlowViewsMixin from viewflow.views import ModelViewSet from .flow import ReportFlow from .models import Report class ReportViewSet(FlowViewsMixin, ModelViewSet): model = Report flow_class = ReportFlow queryset = Report.objects.all() list_display = ['id', 'text', 'state_field'] detail_actions = ['approve', 'reject', 'publish'] ``` -------------------------------- ### Initializing Branches with Specific Data Source: https://docs.viewflow.io/workflow/data_flow.html When splitting work, initialize each branch task with its own data, often derived from process data. ```python split = ( flow.Split() .Next( this.process_post, task_data_source=lambda activation: {'post': post} for post in activation.process.data['posts'], ) .Next(this.join) ) ``` -------------------------------- ### Define Polymorphic User and Client Models Source: https://docs.viewflow.io/orm/json_storage.html Demonstrates polymorphic model inheritance using JSON Store. A base User model with a JSONField is extended by Client proxy models, allowing different real-life objects without multi-table inheritance. ```python from django.contrib.auth.models import AbstractUser from viewflow import jsonstore class User(PolymorphicModel, AbstractUser): data = jsonstore.JSONField(null=True, default=dict) class Client(User): address = jsonstore.CharField(max_length=250) zip_code = jsonstore.CharField(max_length=250) city = jsonstore.CharField(max_length=250) vip = jsonstore.BooleanField() class Meta: proxy = True ``` -------------------------------- ### Custom Transition Form for FSM Viewset Source: https://docs.viewflow.io/fsm/viewset.html Defines a custom form for a specific transition and overrides the viewset to use it. Handles form data during transition. ```Python # forms.py from django import forms from .models import Report class ApproveForm(forms.ModelForm): comment = forms.CharField(widget=forms.Textarea) class Meta: model = Report fields = [] ``` ```Python # viewset.py class ReportViewSet(FlowViewsMixin, ModelViewSet): # ...previous configuration... def get_transition_form_class(self, transition_name): if transition_name == 'approve': return ApproveForm return super().get_transition_form_class(transition_name) def perform_transition(self, instance, transition_name, form=None): flow = self.get_flow_instance(instance) if transition_name == 'approve' and form is not None: instance.approval_comment = form.cleaned_data['comment'] transition = getattr(flow, transition_name) transition() ``` -------------------------------- ### Viewflow Template Tags and Filters Usage Source: https://docs.viewflow.io/workflow/templates.html Demonstrates how to use Viewflow's template tags for generating task and process action URLs, displaying flow diagrams, and checking user permissions. ```django {% load viewflow workflow %} {# Task action URLs #} Assign Execute Unassign {# Process action URLs #} Cancel Process View Details {# Flow diagram #} {% flow_diagram flow_class task=task %} {# Permission checks #} {% if task|can_execute:request.user %} {% endif %} {% if task|can_assign:request.user %} {% endif %} ``` -------------------------------- ### Act Shortcut Source: https://docs.viewflow.io/workflow/api.html Shortcut to access activation data, providing access to the current process and task within an activation context. ```APIDOC ## Class Act ### Description Shortcut to access activation data. ### Properties - **process** (property): Shortcut for lambda activation: activation.process… - **task** (property): Shortcut for lambda activation: activation.task… ``` -------------------------------- ### FSM State Visualization URL Configuration Source: https://docs.viewflow.io/fsm/viewset.html Configures Django URLs to include the state machine chart generated by the FSM Viewset. ```Python # urls.py from django.urls import path, include from .viewset import ReportViewSet urlpatterns = [ path('reports/', include(ReportViewSet().urls)), # Creates /reports/chart/ for the FSM diagram ] ``` -------------------------------- ### Context Variables for Process List Template Source: https://docs.viewflow.io/workflow/templates.html Provides context variables available within the process list template. ```python { 'flow_class': The Flow class, 'process_list': QuerySet of Process instances, 'filter_form': Process filter form (if enabled) } ``` -------------------------------- ### Parallel Execution with flow.Split and flow.Join Source: https://docs.viewflow.io/workflow/writing.html Implements parallel task execution using flow.Split to create branches and flow.Join to synchronize their completion before proceeding. ```python from viewflow import this from viewflow.workflow import flow class MyFlow(flow.Flow): process_class = MyProcess start = ( flow.Start(...) .Next(this.parallel_tasks) ) parallel_tasks = ( flow.Split() .Next(this.task1).Next(this.task2) ) task1 = flow.View(...) .Next(this.join) task2 = flow.View(...) .Next(this.join) join = flow.Join() .Next(this.next_step) next_step = flow.End() ``` -------------------------------- ### Render a Viewflow Form in a Template Source: https://docs.viewflow.io/forms/quick_start.html Use the `{% load viewflow %}` template tag and the `{% render form form.layout %}` tag to display the form. Wrap the form in `` to enable AJAX submission. ```html {% load viewflow %}
{% csrf_token %}
{% render form form.layout %}
``` -------------------------------- ### Passing Data to Subprocesses Source: https://docs.viewflow.io/workflow/data_flow.html Initialize subprocesses with specific seed and data, such as passing the parent process artifact as the subprocess seed. ```python publish_post = flow.Subprocess( PublishFlow.as_subprocess, process_seed=lambda activation: activation.process.artifact, ).Next(this.end) ``` -------------------------------- ### Custom Serializer Per Transition Source: https://docs.viewflow.io/fsm/rest.html Illustrates how to define custom serializer classes for specific transitions within a ViewSet. This allows for different data serialization logic based on the transition action. ```APIDOC ## Custom Serializer Per Transition ### Description Allows specifying a custom serializer class for specific transition actions. ### Method POST ### Endpoint `/your-endpoint/` (inferred from ModelViewSet) ### Parameters #### Path Parameters - **id** (int) - Required - The ID of the object. #### Query Parameters None explicitly defined. #### Request Body - **(fields depend on serializer_class)** - Optional - Data for partial update. ### Request Example ```json { "example": "request body" } ``` ### Response #### Success Response (200) - **(fields depend on serializer_class)** - Description of the updated object. #### Response Example ```json { "example": "response body" } ``` ``` -------------------------------- ### Define HelloWorldProcess Model Source: https://docs.viewflow.io/workflow/quick_start.html Define the process model inheriting from viewflow.workflow.models.Process, adding custom fields like 'text' and 'approved'. ```python from django.db import models from viewflow import jsonstore from viewflow.workflow.models import Process class HelloWorldProcess(Process): text = jsonstore.CharField(max_length=150) approved = jsonstore.BooleanField(default=False) class Meta: proxy = True ``` -------------------------------- ### Custom Process Model with Direct Inheritance Source: https://docs.viewflow.io/workflow/data_flow.html Inherit directly from the Process model to add custom fields and database columns. ```python class ShipmentProcess(Process): carrier = models.ForeignKey(Carrier, on_delete=models.CASCADE) ``` -------------------------------- ### Configure Vite for Library Build Source: https://docs.viewflow.io/crud/css_and_js.html Set up vite.config.js to build your JavaScript components as an IIFE library. This configuration specifies source maps, output directory, and library details. ```javascript import { defineConfig } from 'vite' export default defineConfig({ build: { sourcemap: true, emptyOutDir: false, outDir: 'static/js/', lib: { entry: 'components/index.js', formats: ['iife'], name: 'my_components', fileName: () => "my_components.min.js", }, } }) ``` -------------------------------- ### Process Model Source: https://docs.viewflow.io/workflow/api.html Default viewflow Process model, inheriting from AbstractProcess. Includes exceptions for DoesNotExist and MultipleObjectsReturned. ```APIDOC ## Class Process ### Description Default viewflow Process model. ### Exceptions - **DoesNotExist** - **MultipleObjectsReturned** ``` -------------------------------- ### Including Viewset URLs in Root URL Configuration Source: https://docs.viewflow.io/crud/viewset.html Shows how to integrate a Viewset's URLs into your main Django `urls.py` by including its `.urls` property. ```python viewset = WebsiteViewset() urlpatterns = [ path('', viewset.urls) ] ``` -------------------------------- ### Add Vite Build Script to package.json Source: https://docs.viewflow.io/crud/css_and_js.html Configure your package.json file to include a script for running the Vite build process. This allows you to easily build your project's assets. ```json "scripts": { "vite": "vite build" } ``` -------------------------------- ### Specify Source States Source: https://docs.viewflow.io/fsm/options.html Define one or multiple source states for a transition. Use a set for multiple states. ```python from viewflow.fsm import State @state_field.transition(source={States.NEW, States.DONE}, target=States.CANCELED) def cancel(self): pass ``` -------------------------------- ### User Task Configuration Source: https://docs.viewflow.io/workflow/nodes.html Represents a user interaction step in a flow. It can be configured with a view, annotations for display, permissions, and the subsequent node. ```python class MyFlow(flow.Flow): ... approve = ( flow.View(views.UpdateProcessView.as_view(fields=["approved"])) .Annotation( title=_("Approve"), description=_("Supervisor approvement"), summary_template=_("Message review required"), result_template=( "Message was {{ process.approved|yesno:'Approved,Rejected' }}" ), ) .Permission(auto_create=True) .Next(this.check_approve) ) ... ```