Report Parameters

Developer guide for the Enezaframework reporting engine. Part of the Add Report series.

Table of Contents

  1. Overview
  2. How Parameters Become a Form
  3. Built-in Parameter Types
  4. DateRangeParam
  5. FKFilterParam
  6. DocumentParam
  7. ChoiceParam
  8. QueryParam (Workflow Engine Integration)
  9. Custom Parameters
  10. ParameterSet API
  11. Related Guides

Overview

A report's filters are declared as a ParameterSet of parameter instances and assigned to the report type's parameter_spec. The view builds a Django form from that spec at request time, validates the submission, and asks each parameter for the Q object that filters the report queryset.

Everything lives in enezareporting.parameters.


How Parameters Become a Form

flowchart TD
    SPEC["parameter_spec = ParameterSet(...)"] --> FORM["ParameterSet.get_form_class()"]
    FORM --> RENDER["Filter form rendered"]
    RENDER --> SUBMIT["User submits cleaned_data"]
    SUBMIT --> Q["param.get_filter_q(cleaned_data)"]
    Q --> QUERYSET["Report queryset filtered"]

Built-in Parameter Types

Parameter Form field Use case
DateRangeParam(name, start_field, end_field) Two DateTimeFields Date-range filtering.
FKFilterParam(name, model_field, multiple) ModelMultipleChoiceField / ModelChoiceField FK-based filtering.
DocumentParam(name, model) ModelChoiceField / integer input Single document selection.
ChoiceParam(name, choices, multiple) ChoiceField / MultipleChoiceField Static choice filtering.
QueryParam(name, saved_query_id) ModelChoiceField / CharField Workflow engine SavedQuery.

DateRangeParam

Produces start_date and end_date form fields and applies __gte / __lte filters.

python
DateRangeParam(
    name="date_range",          # logical name
    start_field="date_placed",  # model field for the __gte filter
    end_field="date_placed",    # model field for the __lte filter (defaults to start_field)
    required=False,
)

end_field defaults to start_field (enezareporting/parameters.py:82-92). If start_field is empty, the parameter contributes no filter.


FKFilterParam

python
FKFilterParam(
    name="customer",            # form field name
    model_field="customer",     # FK field path on the report model
    multiple=True,              # multi-select vs. single-select
)

FK traversal is supported: model_field="customer__region". The parameter resolves the related model and applies __in (multiple) or an exact match (single) (enezareporting/parameters.py:162-184). Pass queryset_filter_func to restrict the choices.


DocumentParam

python
DocumentParam(
    name="document_id",         # defaults to "document_id"
    model=Invoice,              # model for choices
    lookup_field="pk",          # value field
    display_field="",           # optional field to display
    required=True,              # default is True
)

Without model, the parameter degrades to a plain integer input (enezareporting/parameters.py:214-233).


ChoiceParam

python
ChoiceParam(
    name="status",
    choices=[("open", "Open"), ("closed", "Closed")],
    multiple=False,
)

Applies status__in (multiple) or status=<value> (single) to the queryset (enezareporting/parameters.py:243-280).


QueryParam (Workflow Engine Integration)

When enezaworkflowengine is installed and QUERY_INTEGRATION_ENABLED is True, the parameter shows available SavedQuery records. Otherwise it degrades to a text field.

python
QueryParam(
    name="saved_query_id",
    workflow_name="sales_filter",  # optional: filter queries by workflow
    saved_query_id=5,              # optional: fixed query (no form field shown)
)

See Reporting Settings for QUERY_INTEGRATION_ENABLED.


Custom Parameters

Subclass BaseParameter and implement get_form_field() and get_filter_q():

python
from django import forms
from django.db.models import Q
from enezareporting.parameters import BaseParameter


class StatusParam(BaseParameter):
    def get_form_field(self):
        return forms.ChoiceField(
            choices=[("open", "Open"), ("closed", "Closed")],
            required=self.required,
            label=self.label,
        )

    def get_filter_q(self, cleaned_data):
        value = cleaned_data.get(self.name)
        if value:
            return Q(status=value)
        return None

BaseParameter contract (enezareporting/parameters.py:42-68):

Method Purpose
get_form_field() Return the Django form field for this parameter.
get_filter_q(cleaned_data) Return a Q object, or None.
get_value_from_form(cleaned_data) Extract the value from cleaned data.
get_form_field_name() Return the form field name (defaults to self.name).

ParameterSet API

ParameterSet(*parameters) is defined in enezareporting/parameters.py:366-491:

Method Returns
get_form_class(report_model=None, initial=None) A generated Django Form class.
get_filters(cleaned_data) Tuple of (Q, kwargs) or (None, None).
get_initial() Default initial values (date range).
get_parameter(name) The parameter with that name, or None.
get_parameters_of_type(param_type) All parameters of a given class.

get_form_class handles DateRangeParam and DocumentParam specially, and only resolves FKFilterParam when a report_model is available (enezareporting/parameters.py:404-429).