Skip to content

Quick start

Requirements

  • Python 3.12+
  • Django 5.2 or 6.0

The API uses Django's built-in session auth; you do not need Django REST Framework.

Install

pip install django-report-builder

Then in settings.py:

INSTALLED_APPS = [
    ...
    "report_builder",
]

And in urls.py:

from django.urls import include, path

urlpatterns = [
    ...
    path("report_builder/", include("report_builder.urls")),
]

Run migrations:

python manage.py migrate

Now log into Django admin (/admin/) as a staff user, then visit /report_builder/.

Settings

Limit which models are exposed

# Allow only specific models (app_label.model_name, lowercase)
REPORT_BUILDER_INCLUDE = ["hr.user", "billing.invoice"]

# Or block specific models
REPORT_BUILDER_EXCLUDE = ["finance.account"]

Per-model field control

Add a ReportBuilder inner class to a model — the syntax mirrors Django's Meta:

class Order(models.Model):
    ...

    class ReportBuilder:
        fields = ("id", "customer", "total")  # explicit allow-list
        exclude = ("internal_notes",)         # block specific fields
        extra = ("display_total",)            # methods/properties to expose
        defaults = ("id", "customer")         # default-on display fields
        filters = ("customer", "status")      # fields that surface as filters

fields and exclude are mutually exclusive; pick one. extra is how Python properties get into reports — they're opt-in. defaults and filters are advisory metadata — they're returned by the API for frontends that want to use them.

Custom model managers

Use a different manager globally:

REPORT_BUILDER_MODEL_MANAGER = "on_site"

Or per-model, by adding the attribute on the model class:

class Order(models.Model):
    on_site = OnSiteManager()
    report_builder_model_manager = on_site

Export to Report admin action

Off by default. Turn on with:

REPORT_BUILDER_GLOBAL_EXPORT = True

Users can then select rows on a Django admin change-list and export them through a chosen report — the report's filters are bypassed in favor of the selected primary keys.

Asynchronous report generation

For reports that take long enough to risk an HTTP timeout, hand them off to a background worker:

REPORT_BUILDER_ASYNC_REPORT = True

The dispatch layer targets the standard django.tasks framework. Pick whichever backend fits your project:

  1. Django 6.0+ built-in django.tasks — no extra package needed. Configure a backend via the TASKS setting (the bundled in-memory / database backends are aimed at dev and testing).
  2. django-vtasks — a faster asyncio-worker backend for the same framework that can optionally be embedded inside an ASGI app instead of running a separate worker. pip install django-report-builder[vtasks], then configure the backend via the TASKS setting (see vtasks' README).
  3. django-tasks — a drop-in backport of the built-in framework, for projects still on Django 5.2. pip install django-report-builder[tasks].
  4. Celery — if you already run Celery, the dispatch layer detects it and hands off via shared_task. Install with pip install django-report-builder[celery].
  5. Inline (synchronous) — used when none of the above is installed; effectively the same as REPORT_BUILDER_ASYNC_REPORT = False.

The dispatch layer auto-detects which is available in roughly the order above. Switching is just pip install + a backend swap in the TASKS setting; no report-builder code changes.

Email when an async report is ready

REPORT_BUILDER_EMAIL_NOTIFICATION = True
REPORT_BUILDER_EMAIL_SUBJECT = "Your report is ready"

Standard Django mail config applies (EMAIL_BACKEND or EMAIL_HOST, plus DEFAULT_FROM_EMAIL). The email template is email/email_report.html and can be overridden in your project's templates. {{ report }} and {{ name }} are interpolated.

The bundled SPA still downloads the file directly — to actually use the email-only flow, build (or extend) your own frontend.

Scheduled reports

Recurring report runs are an opt-in app on top of Celery beat:

  1. pip install django-celery-beat
  2. Add django_celery_beat and report_builder_scheduled to INSTALLED_APPS
  3. Schedule a Celery beat task to run report_builder_scheduled.tasks.report_builder_check_if_scheduled_report every ~10 minutes — it dispatches the actual report jobs

Disable the bundled frontend

If you're shipping your own SPA against the report builder API, hide the built-in one:

REPORT_BUILDER_FRONTEND = False