Workflow Type Registry Quick Start

Developer guide for the Enezaframework workflow engine. Part of the Workflow series.

Table of Contents

  1. Overview
  2. Built-in Workflow Types
  3. Using the Generic Query Builder
  4. What Happens Without a Workflow Name
  5. Adding a Project Workflow Type
  6. Related Guides

Overview

The registry needs no setup for the built-in workflow types. You open the generic query builder with a workflow_name parameter; the framework resolves the allowed models from WorkflowTypeRegistry and renders the filter UI. No custom view is required.

flowchart LR
    A["Open /workflow/query-builder/<br/>?workflow_name=ExpenseWorkflow"] --> B["QueryBuilderMixin.get_workflow_name()"]
    B --> C["WorkflowTypeRegistry.get_allowed_models()"]
    C --> D["Allowed model configs"]
    D --> E["Filter definitions + aggregate options"]
    E --> F["query_builder.html"]

Built-in Workflow Types

Defined in WorkflowTypeRegistry._framework_registry (enezaworkflowengine/services/workflow_type.py:36-99):

Workflow Name Primary Model App
PurchaseOrderWorkflow PurchaseOrder purchasing
InvoiceWorkflow Frameworktestdocument frameworkapp
CreditCardWorkflow CreditCardTransaction accounting
ExpenseWorkflow Expense accounting
LeaveApplicationWorkflow LeaveApplication hr

Their values must also exist in Workflownames (enezaworkflowengine/models/choices.py:24-29) so they can be selected in the UI and stored on SavedQuery.workflow.


Using the Generic Query Builder

Open the builder with the workflow name:

text
/workflow/query-builder/?workflow_name=ExpenseWorkflow

The generic views read the registry automatically and:

  • resolve the allowed models for the workflow,
  • generate filter definitions per model (get_model_filters),
  • generate aggregate options per model (get_aggregate_options),
  • render the query builder UI,
  • save queries with the workflow name attached.
python
# enezaworkflowengine/views/querybuilder.py:55-76
class BuildQueryView(QueryBuilderMixin, LoginRequiredMixin, TemplateView):
    template_name = 'query_builder.html'

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        workflow_name = self.get_workflow_name()
        allowed_models = self.get_allowed_models()
        ctx['models_list'] = allowed_models
        ctx['workflow_name'] = workflow_name
        filters_by_model = {
            m['slug']: self.get_model_filters(m['app_label'], m['model_name'], model_config=m)
            for m in allowed_models
        }
        for m in allowed_models:
            filters_by_model[m['slug']]['aggregates'] = self.get_aggregate_options(m)
        ctx['filters_by_model_json'] = json.dumps(filters_by_model)
        ctx['models_list_json'] = json.dumps(allowed_models)
        return ctx

URL naming. The engine is mounted at the /workflow/ path prefix with the URL namespace enezaworkflowengine (enezaworkflowengine/urls.py:47). Reverse the builder with enezaworkflowengine:build_query, and the save endpoint with enezaworkflowengine:save_query.


What Happens Without a Workflow Name

If no workflow_name is supplied (request parameter or view attribute), get_allowed_models() returns the fallback _default_models (workflow_type.py:104-134, :200-202):

Slug Model App
user User enezacommon
entity Entity enezaframework

This keeps the builder usable for generic queries. To scope the builder to a workflow, always pass workflow_name.


Adding a Project Workflow Type

A project-defined workflow is three small edits:

  1. Define WORKFLOW_TYPE_REGISTRY in the workflowconfig/type_registry.py submodule (or a single workflowconfig.py).
  2. Point MY_PROJECT_WORKFLOWS_CONFIG at that class in settings.py.
  3. Add the workflow value to a Workflownames subclass and point MY_PROJECT_WORKFLOWS_NAME at it.
python
# myproject/workflowconfig.py
from enezaworkflowengine.models.choices import Workflownames


class ProjectWorkflowNames(Workflownames):
    SALESORDERWORKFLOW = 'SalesOrderWorkflow', 'Sales Order Workflow'


class WorkflowTypeConfig:
    WORKFLOW_TYPE_REGISTRY = {
        'SalesOrderWorkflow': [
            {
                'slug': 'sales_order',
                'label': 'Sales Order',
                'app_label': 'sales',
                'model_name': 'SalesOrder',
                'relationships': [
                    {
                        'field_name': 'customer',
                        'label': 'Customer',
                        'type': 'fk',
                        'related_app': 'crm',
                        'related_model': 'Customer',
                    },
                ],
            },
        ],
    }
python
# myproject/settings.py
MY_PROJECT_WORKFLOWS_NAME = 'myproject.workflowconfig.ProjectWorkflowNames'
MY_PROJECT_WORKFLOWS_CONFIG = 'myproject.workflowconfig.WorkflowTypeConfig'

Full details are in Workflow Project Configuration.