Using report builder
A staff user with is_staff = True who can log into Django admin can use the
report builder. Visit /report_builder/ after logging in.
The dashboard
The home view lists every report you have permission to see. A search box above the table filters by name. Click a report's name to open it, or Add Report to create a new one. Each row also has copy and delete actions.
Creating a report
Add Report asks for two things:
- Name — what users see on the dashboard
- Root model — the Django model the report is anchored on. Filters and display fields all hang off this; relations are reachable, but the starting point matters
Save and you'll land on the editor.
The editor
The editor is four tabs across the top — Display, Filter, Report, Options. The right-hand sidebar lists every field reachable from the root model.
Display
This is the column list. From the sidebar:
- Click a related-model node in the tree to expand it; click its name to load that model's fields into the bottom of the sidebar
- Click the + next to a field to add it as a column
- Drag the row's grip handle to reorder columns within the table
- Edit Name to rename the column header
- Sort + Desc? control the ORM ordering.
Sortis a positive integer — lower numbers sort first (so1, 2, 3orders by the first column, then the second, etc.). Leave it blank (or0) to skip sorting on that column. - Aggregate turns the column into
Sum/Count/Avg/Max/Min - Format applies a stored format string (configured under
/admin/report_builder/format/) - Total and Group add a totals row and
GROUP BYsemantics
Filter
Same sidebar workflow — click + next to a field to add it as a filter. Each filter row has:
- A Filter type dropdown (
exact,gt,icontains,range,relative_range,isnull, regex, etc.) - A Value input that adapts to the field type — text fields get a
textbox, dates get a date input, booleans get a checkbox,
relative_rangegets a number + unit picker - An Exclude checkbox to invert the match (
.exclude()instead of.filter())
Report
Generate the result set in-browser. From there you can export to xlsx or
csv — synchronously by default, or as a background task if
REPORT_BUILDER_ASYNC_REPORT is on (the export button shows progress and
the file becomes available on the same screen when ready).
Options
- Description — visible on the report list
- Distinct — adds
.distinct()to the underlying queryset; useful when joining many-to-many relations produces duplicate rows - Delete and Copy for the report
Tips
- If a model isn't appearing in the sidebar, check
REPORT_BUILDER_INCLUDE/REPORT_BUILDER_EXCLUDE, plus thefields/excludelists in the model'sReportBuilderinner class. - Properties (Python
@propertymethods on a model) won't show up unless you list them inReportBuilder.extra— and they slow report generation noticeably, since each row is computed in Python rather than the database. relative_rangefilters express a window relative to "now". The UI shows a number plus a unit ("7 days ago"); under the hood the unit string is stored infilter_valueand a negative-seconds offset infilter_delta(so "7 days ago" is-604800). The backend evaluates it againstnow()at run time, so the report stays current as it ages.