Workflow Query Quick Start
Developer guide for the Enezaframework workflow engine. Part of the Workflow series.
Table of Contents
- Overview
- Step 1 — Define an Aggregate-Enabled Query
- Step 2 — Save It Through the API
- Step 3 — Execute with Object ID
- Step 4 — Use It in the Workflow Engine
- Related Guides
Overview
This quick start builds one query that filters documents by an aggregate (total line amount) and executes it scoped to a single document. No configuration is required in the workflow engine for the object-ID behavior — the engine extracts the ID itself.
flowchart LR
A["Define filters_json<br/>annotations + rules"] --> B["Save via SaveQueryView"]
B --> C["SavedQuery stored<br/>with workflow"]
C --> D["execute(object_id=...)"]
C --> E["Condition step<br/>auto object_id"]
D --> F["Scoped results"]
E --> FStep 1 — Define an Aggregate-Enabled Query
{
"condition": "AND",
"annotations": [
{"function": "sum", "field": "line_total", "related_model": "lines", "alias": "total"},
{"function": "count", "field": "id", "related_model": "lines", "alias": "item_count"}
],
"rules": [
{"id": "total", "field": "total", "type": "double", "operator": "greater", "value": "500"},
{"id": "item_count", "field": "item_count", "type": "integer", "operator": "greater", "value": "3"}
]
}
This matches documents whose line amounts total more than 500 and that have more than 3 line items. The rule field values must equal the annotation alias values.
Step 2 — Save It Through the API
POST the query to SaveQueryView (enezaworkflowengine:save_query):
{
"name": "Large Orders",
"model_slug": "frameworktestdocument",
"workflow_name": "InvoiceWorkflow",
"query": {
"condition": "AND",
"annotations": [
{"function": "sum", "field": "amount", "related_model": "lines", "alias": "total_amount"}
],
"rules": [
{"id": "total_amount", "field": "total_amount", "type": "double", "operator": "greater", "value": "1000"}
]
}
}
Alternatively, send annotations as a separate top-level key — the view merges it into filters_json before saving (enezaworkflowengine/views/querybuilder.py:104-107):
{
"name": "Large Orders",
"model_slug": "frameworktestdocument",
"workflow_name": "InvoiceWorkflow",
"query": {
"condition": "AND",
"rules": []
},
"annotations": [
{"function": "sum", "field": "amount", "related_model": "lines", "alias": "total_amount"}
]
}
Step 3 — Execute with Object ID
GET /workflow/savedquery/5/?execute=1&object_id=550e8400-e29b-41d4-a716-446655440000
SaveQueryDetailView reads object_id from the query string and forwards it to the query (views/querybuilder.py:231-234):
object_id = self.request.GET.get('object_id')
queryset = self.object.execute(object_id=object_id)
object_id is a string (UUID for EnezaModel subclasses); Django's ORM accepts it directly in pk=....
Step 4 — Use It in the Workflow Engine
No configuration is needed. When a condition step evaluates, the engine supplies the ID automatically:
# Web path: services/step_handlers.py:242 — has workflow_instance
queryset = condition_query.get_queryset(object_id=workflow_instance.object_id)
# Celery path: tasks/workflow_tasks.py:253-254 — delegates to the service function
from enezaworkflowengine.services.condition_step import evaluate_condition_for_document
result = evaluate_condition_for_document(workflow_instance.document, condition_query)
# -> evaluate_condition_for_document extracts str(document.pk) and passes it on
sequenceDiagram
participant W as WorkflowInstance
participant H as ConditionStepHandler
participant Q as SavedQuery
W->>H: STEP_ENTERED
H->>Q: get_queryset(object_id=workflow_instance.object_id)
Q-->>H: count
H-->>W: CONDITION_TRUE or CONDITION_FALSE