Report Generators

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

Table of Contents

  1. Overview
  2. Generator Map
  3. The Generator Contract
  4. TabularReportGenerator
  5. DocumentReportGenerator
  6. DrillDownReportGenerator
  7. Using Generators Directly
  8. Related Guides

Overview

Generators do the imperative work: fetch data, aggregate, format, and return a structured response. The unified *ReportView base instantiates the right generator for your report type automatically, but generators are plain classes you can also use from a management command, API endpoint, or background task.


Generator Map

Generator Module Report base
TabularReportGenerator enezareporting.generators.tabular TabularReportView (+ SummaryReportView, DetailedReportView)
CrosstabReportGenerator enezareporting.generators.crosstab CrosstabReportView
TimeSeriesReportGenerator enezareporting.generators.time_series TimeSeriesReportView
DocumentReportGenerator enezareporting.generators.document DocumentReportView
DrillDownReportGenerator enezareporting.generators.drilldown DrillDownReportView

CrosstabReportGenerator and TimeSeriesReportGenerator subclass TabularReportGenerator, so the tabular methods below apply to them as well. ListViewReportGenerator (also in generators/tabular.py) backs the legacy list view.

flowchart LR
    TAB["TabularReportGenerator"] --> CROSS["CrosstabReportGenerator"]
    TAB --> TS["TimeSeriesReportGenerator"]
    TAB --> LIST["ListViewReportGenerator"]
    DOC["DocumentReportGenerator"]
    DD["DrillDownReportGenerator"]

The Generator Contract

A generator returns a response shaped as:

python
{
    "data": [...],            # rows, or a document dict for DocumentReport
    "columns": [...],         # column metadata
    "metadata": {...},        # totals, stats, extra info
    "chart_settings": [...],  # chart configuration
}

The view consumes this and passes it to the template. See Report Templates.


TabularReportGenerator

enezareporting.generators.tabular.TabularReportGenerator

python
from enezareporting.generators.tabular import TabularReportGenerator

gen = TabularReportGenerator(
    report_model=SalesLine,
    columns=["item_description", "__total__"],
    group_by="item_code",
    start_date=start,
    end_date=end,
    date_field="date_placed",
)

data = gen.get_report_data()        # list of row dicts
columns = gen.get_columns_data()    # column metadata
full = gen.get_full_response()      # {data, columns, metadata, chart_settings}

DocumentReportGenerator

enezareporting.generators.document.DocumentReportGenerator

python
from enezareporting.generators.document import DocumentReportGenerator

gen = DocumentReportGenerator(
    header_model=Invoice,
    lines_related_name="lines",
    header_fields=["invoice_number", "customer"],
    line_columns=["item", "quantity", "line_total"],
    line_total_fields=["line_total"],
)

result = gen.get_report_data(document_id=42)
# result = {
#     "header": {"invoice_number": {"label": "Invoice #", "value": "INV-001"}, ...},
#     "lines": [{"item": "Widget", "quantity": 5, "line_total": 100}, ...],
#     "totals": {"line_total": 350},
# }

fetch_document raises ImproperlyConfigured when header_model is not set (enezareporting/generators/document.py:67-84).


DrillDownReportGenerator

enezareporting.generators.drilldown.DrillDownReportGenerator

python
from enezareporting.generators.drilldown import DrillDownReportGenerator
from enezareporting.report_types import HierarchyLevel

gen = DrillDownReportGenerator(
    hierarchy=[
        HierarchyLevel(model=Region, display_field="name"),
        HierarchyLevel(model=Branch, display_field="name", parent_field="region"),
    ],
)

root = gen.get_report_data(level_index=0)                  # root level
child = gen.get_report_data(level_index=1, path_ids=[1])   # children of region 1

can_drill = gen.can_drill_down(level_index=0, row_id=1)

Using Generators Directly

Generators are usable outside views — for example in a management command or export job:

python
from datetime import datetime
from enezareporting.generators.tabular import TabularReportGenerator
from myapp.models import SalesLine


def export_sales_report():
    gen = TabularReportGenerator(
        report_model=SalesLine,
        columns=["item_description", "__total__"],
        start_date=datetime(2024, 1, 1),
        end_date=datetime(2024, 12, 31),
        date_field="date_placed",
    )
    return gen.get_report_data()