Workflow Model Configuration

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

Table of Contents

  1. Overview
  2. Model Configuration Dict
  3. Relationships
  4. Full Schema Reference
  5. Relationship Type Behavior
  6. Explicit vs Auto-Discovered vs Empty
  7. Related Guides

Overview

Each WorkflowTypeRegistry entry maps a workflow name to a list of model configuration dicts. Each dict tells the query builder which model to expose, how to label it, and which related models may be filtered. The same shape is consumed by QueryBuilderMixin.get_allowed_models() and get_model_filters().


Model Configuration Dict

python
{
    'slug': 'purchase_order',
    'label': 'Purchase Order',
    'app_label': 'purchasing',
    'model_name': 'PurchaseOrder',
    'relationships': [
        {
            'field_name': 'vendor',
            'label': 'Vendor',
            'type': 'fk',
            'related_app': 'purchasing',
            'related_model': 'Vendor',
        },
    ],
}
Key Required Description
slug Yes Unique identifier for the model, used by the UI/JS and by SaveQueryView to find the selected model.
label Yes Human-readable display name.
app_label Yes Django app label, for example purchasing.
model_name Yes Django model class name, for example PurchaseOrder.
relationships No Explicit relationship definitions. Omit to auto-discover.

SaveQueryView resolves the chosen model with next((m for m in allowed_models if m['slug'] == model_slug), None) (enezaworkflowengine/views/querybuilder.py:101), so slug must be unique within a workflow.


Relationships

The relationships list defines which related models are exposed as filter groups.

python
{
    'field_name': 'vendor',       # FK/M2M field name on the primary model
    'label': 'Vendor',            # display label for the relationship group
    'type': 'fk',                 # 'fk' or 'm2m'
    'related_app': 'purchasing',  # related model's app label
    'related_model': 'Vendor',    # related model's class name
}
Field Description
field_name The FK or M2M field name on the primary model. Also used as the lookup prefix (vendor__).
label Display label for the relationship group. Falls back to a title-cased field_name.
type 'fk' for ForeignKey, 'm2m' for ManyToMany.
related_app Django app label of the related model.
related_model Class name of the related model.

The builder expands each relationship into filter definitions for the related model's fields, using <field_name>__<field> lookups (enezaworkflowengine/views/mixin.py:288-301).


Full Schema Reference

python
{
    # Required
    'slug': str,
    'label': str,
    'app_label': str,
    'model_name': str,

    # Optional — omit for auto-discovery, use [] to disable
    'relationships': [
        {
            # Required per relationship
            'field_name': str,
            'label': str,
            'type': str,            # 'fk' or 'm2m'
            'related_app': str,
            'related_model': str,
        },
    ],
}

Relationship Type Behavior

type Behavior
'fk' ForeignKey — traverses __ lookups to filter fields on the related model.
'm2m' ManyToMany — same __ traversal, joined through the through-table.

Both are emitted as a lookup_prefix of <field_name>__, so the generated filter IDs are identical in shape.


Explicit vs Auto-Discovered vs Empty

The behavior depends on whether the relationships key is present (enezaworkflowengine/views/mixin.py:284-314):

flowchart TD
    CFG["model_config passed to get_model_filters()"] --> HAS{"'relationships' key present?"}
    HAS -->|Yes| EXPLICIT["Use the explicit list<br/>even when it is empty []"]
    HAS -->|No| AUTO["Auto-discover FK + M2M<br/>from model._meta"]
    EXPLICIT --> BUILD["Build 'related' filter groups"]
    AUTO --> BUILD
Situation Use
Control which relationships appear, custom labels, limit traversal depth Explicit list
Expose every FK/M2M with default verbose_name labels Omit the key
Model has no relationships to expose, or you want to disable auto-discovery 'relationships': []

Omitting the key and setting [] are not equivalent. Omission triggers auto-discovery; an empty list suppresses it.