QueryBuilderMixin Integration
Developer guide for the Enezaframework workflow engine. Part of the Workflow series.
Table of Contents
- Overview
- How the Workflow Name Is Resolved
- Generic Query Views
- What the Views Build
- Usage
- 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):
GETparameterworkflow_namePOSTparameterworkflow_name- The view's
self.workflow_nameattribute 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):
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:
# 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
/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).