QueryBuilderMixin Integration

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

Table of Contents

  1. Overview
  2. How the Workflow Name Is Resolved
  3. Generic Query Views
  4. What the Views Build
  5. Usage
  6. Related Guides

Overview

QueryBuilderMixin (enezaworkflowengine/views/mixin.py:38) is the bridge between the registry and the generic query builder views. It resolves a workflow name, asks WorkflowTypeRegistry for the allowed models, and turns each model into filter and aggregate definitions. The generic views (BuildQueryView, SaveQueryView, and the saved-query CRUD views) consume those results — no per-workflow view is needed.


How the Workflow Name Is Resolved

flowchart TD
    START["get_workflow_name()"] --> REQ{"request.GET['workflow_name']<br/>or request.POST['workflow_name']?"}
    REQ -->|Yes| USE["Use request value"]
    REQ -->|No| ATTR{"self.workflow_name set?"}
    ATTR -->|Yes| USE2["Use view attribute"]
    ATTR -->|No| NONE["None -> default models"]

Priority (views/mixin.py:51-65):

  1. GET parameter workflow_name
  2. POST parameter workflow_name
  3. The view's self.workflow_name attribute
  4. None → fallback _default_models (User, Entity)

get_allowed_models() then calls WorkflowTypeRegistry.get_allowed_models(workflow_name) (views/mixin.py:67-81).


Generic Query Views

View Route / URL name Purpose
BuildQueryView /workflow/query-builder/ · enezaworkflowengine:build_query Query builder UI. Reads ?workflow_name=.
SaveQueryView /workflow/save-query/ · enezaworkflowengine:save_query POST endpoint that persists a SavedQuery.
SaveQueryListView /workflow/savedquery/ · enezaworkflowengine:savedquery_list Lists saved queries for the entity/user.
SaveQueryDetailView /workflow/savedquery/<pk>/ · enezaworkflowengine:savedquery_detail View, edit, and execute a saved query.
SaveQueryDeleteView /workflow/savedquery_delete/<pk>/ · enezaworkflowengine:savedquery_delete Deletes a saved query.

BuildQueryView and SaveQueryView are registered manually (enezaworkflowengine/urls.py:68-69). The list/detail/delete views are registered with @auto_url_register and use the model prefix savedquery.

SaveQueryView.post() sets self.workflow_name from the request body, then resolves the selected model by slug (views/querybuilder.py:94-103):

python
workflow_name = data.get('workflow_name', '').strip()
self.workflow_name = workflow_name if workflow_name else None
allowed_models = self.get_allowed_models()
model_info = next((m for m in allowed_models if m['slug'] == model_slug), None)
if not model_info:
    return JsonResponse({'error': 'Invalid model selected'}, status=400)

What the Views Build

For each allowed model, the view produces a filter map keyed by slug, then attaches an aggregates structure:

python
# enezaworkflowengine/views/querybuilder.py:68-74
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)

Each get_model_filters() result has direct and related arrays; get_aggregate_options() adds a related_models + functions structure. See Workflow Aggregate Metadata API.


Usage

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

The view then automatically:

  • loads allowed models via WorkflowTypeRegistry.get_allowed_models(),
  • generates filter definitions per model,
  • renders the query builder UI,
  • saves queries with the workflow name, so later filtering by ?workflow= works (SaveQueryListView.get_queryset(), views/querybuilder.py:158-161).