RamezIssac/django-slick-reporting

The Reporting Engine for Django. Create dashboards and standalone Reports and Charts.

analysis
analytics
charting
charts
customisable
django
easy-to-use
pivot-tables
python
reporting
time-series
# Django Slick Reporting ### The one-stop reporting engine for Django — every report is one small declarative class. [![PyPI version](https://img.shields.io/pypi/v/django-slick-reporting.svg)](https://pypi.org/project/django-slick-reporting) [![CI](https://github.com/ra-systems/django-slick-reporting/actions/workflows/django.yml/badge.svg)](https://github.com/ra-systems/django-slick-reporting/actions/workflows/django.yml) [![Python versions](https://img.shields.io/pypi/pyversions/django-slick-reporting.svg)](https://pypi.org/project/django-slick-reporting) [![Django versions](https://img.shields.io/pypi/djversions/django-slick-reporting)](https://pypi.org/project/django-slick-reporting) [![License](https://img.shields.io/pypi/l/django-slick-reporting.svg)](https://github.com/ra-systems/django-slick-reporting/blob/develop/LICENSE.md) [![Docs](https://img.shields.io/readthedocs/django-slick-reporting)](https://django-slick-reporting.readthedocs.io/) Grouped totals, time series, crosstabs and charts — declared once, generated for you. Change one line of the class, get a totally different report.
pip install django-slick-reporting
[**Live Demo**](https://django-slick-reporting.com/) · [**Documentation**](https://django-slick-reporting.readthedocs.io/) · [**Quickstart**](#quickstart)

The shape of a report

A report is a small declarative class: every attribute maps to a visible part of the output. Watch what happens below as we change one line at a time — same SalesTransaction model throughout.

A group-by report

# views.py
from django.db.models import Sum
from slick_reporting.views import ReportView, Chart
from slick_reporting.fields import ComputationField
from .models import SalesTransaction


class ProductSales(ReportView):
    report_model = SalesTransaction
    date_field = "date"
    group_by = "product"

    columns = [
        "name",
        ComputationField.create(
            Sum, "value",
            name="value__sum",
            verbose_name="Total sold $",
        ),
    ]

    chart_settings = [
        Chart(
            "Total sold $", Chart.BAR,
            data_source=["value__sum"],
            title_source=["name"],
        ),
    ]
# urls.py
path("product-sales/", ProductSales.as_view()),
Product sales report grouped by product Filter form, chart, sortable table and CSV export — all generated from the class.

Change one line → a different report

group_by accepts any field or relation path. Swap "product" for "client":

class ClientSales(ReportView):
    report_model = SalesTransaction
    date_field = "date"
    group_by = "client"   # ← the only change

    columns = [
        "name",
        ComputationField.create(
            Sum, "value",
            name="value__sum",
            verbose_name="Total sold $",
        ),
    ]

    chart_settings = [
        Chart(
            "Total sold $", Chart.BAR,
            data_source=["value__sum"],
            title_source=["name"],
        ),
    ]
Same report regrouped by client Same class, new grouping — a completely different report.

Add two lines → a monthly time series

class MonthlyProductSales(ReportView):
    report_model = SalesTransaction
    date_field = "date"
    group_by = "product"
    columns = ["name"]

    time_series_pattern = "monthly"  # ← new
    time_series_columns = [          # ← new
        ComputationField.create(
            Sum, "value",
            name="value__sum",
            verbose_name="Total sold $",
        ),
    ]

    chart_settings = [
        Chart(
            "Total sold $", Chart.LINE,
            data_source=["value__sum"],
            title_source=["name"],
        ),
    ]
`"monthly"` can be `"daily"`, `"weekly"`, `"yearly"` or a custom pattern.
Monthly time-series report One column per month, computed per period.

Or pivot it → a crosstab matrix

class ProductSalesCrosstab(ReportView):
    report_model = SalesTransaction
    date_field = "date"
    group_by = "product"

    crosstab_field = "client"
    crosstab_columns = [
        ComputationField.create(
            Sum, "value",
            name="value__sum",
            verbose_name="Total sold $",
        ),
    ]

    columns = [
        "name",
        "__crosstab__",
        ComputationField.create(
            Sum, "value",
            name="value__total",
            verbose_name="Total",
        ),
    ]
Crosstab matrix report Products as rows, clients as columns, totals at the intersections.

More shapes — list views, custom querysets, precomputed crosstabs, time-series × crosstab combinations — in the documentation.


Charts, from the same class

Declare the calculation once; switch the visualization by changing a single argument — no new query, no new template.

Switching chart types by changing one argument

Any chart engine

Set chart_engine on the report (or per Chart). The same data renders through your engine of choice:

Highcharts
chart_engine="highcharts"
Chart.js
chart_engine="chartsjs"
ApexCharts
chart_engine="apexcharts"
Highcharts Chart.js ApexCharts

Any other JS charting library can be plugged in as a custom engine.

Dashboards

Compose any report into a page as a self-contained widget — chart, table, or both — with one template tag:

{% load slick_reporting_tags %}

{% get_widget_from_url url_name="product-sales" %}
{% get_widget_from_url url_name="monthly-product-sales" chart_id=1 display_table=False title="Chart only" %}

See the live dashboard example.

Ask the data — the LLM assistant

New: let your users ask questions in plain English and get an answer backed by a live report, with proofs. The assistant plans a report configuration, runs it through the same reporting engine, and answers with the numbers — you can inspect the generated report and the raw response right on the dashboard.

Ask the data: a plain-English question answered with a live report and proofs

Works with OpenRouter (free models included), any OpenAI-compatible endpoint, or a local llama.cpp server. Docs · Try it live

Features

  • Every report shape — simple aggregates, group-by, time-series, crosstab/pivot, and combinations of them.
  • Charts included — Highcharts, Chart.js and ApexCharts wrappers, plus pluggable custom engines.
  • Custom calculations — build reusable computation fields, chain dependencies, compute percentages and balances.
  • Dashboards — drop any report onto a page as a self-contained widget with a template tag.
  • Ask-the-data assistant — an optional LLM assistant answers plain-English questions with a generated report (docs).
  • Model-optional — report against a Django model, a traversed relation, a raw SQL table, or precomputed/aggregated data.
  • Fast & extendable — optimized queries, CSV export out of the box, and hooks for everything.

Installation

pip install django-slick-reporting

Add it to INSTALLED_APPS and you're ready:

INSTALLED_APPS = [
    ...,
    "crispy_forms",
    "crispy_bootstrap5",
    "slick_reporting",
]

Quickstart

The group-by report above is a complete working example — declare the class, wire one URL, done. Prefer data without a view? The same configuration works on the low-level engine:

from slick_reporting.generator import ReportGenerator

report = ReportGenerator(
    report_model=SalesTransaction,
    group_by="product",
    columns=["name", "__total__"],
)
report.get_report_data()
# -> [{'name': 'Product 1', '__total__': 56}, {'name': 'Product 2', '__total__': 43}, ...]

Demo site

Live at django-slick-reporting.com, or run it locally:

git clone https://github.com/ra-systems/django-slick-reporting.git
python -m venv .venv && source .venv/bin/activate

cd django-slick-reporting/demo_proj
pip install -r requirements.txt
python manage.py migrate
python manage.py create_entries   # generates demo data
python manage.py runserver

To try the Ask the data assistant, put an OpenRouter key in the OPENROUTER_API_KEY environment variable (a demo_proj/.env file works too). The demo defaults to the free-tier model nex-agi/nex-n2.5-mini:free; switch models with the SLICK_REPORTING_LLM_MODEL environment variable — e.g. SLICK_REPORTING_LLM_MODEL=google/gemma-4-31b-it:free python manage.py runserver. Browse free models at openrouter.ai/models.

Documentation

Full documentation lives on Read the Docs. Build it locally with:

cd docs
pip install -r requirements.txt
sphinx-build -b html source build

Running the tests

git clone [email protected]:ra-systems/django-slick-reporting.git
cd django-slick-reporting/tests
python -m pip install -e ..
python runtests.py
# coverage:
coverage run --include=../* runtests.py && coverage html

Contributing

PRs and reviews are most welcome. We follow Django's contributing guidelines. If the project is useful to you, please consider giving it a star — it keeps the project visible and motivated.

Authors

You might also like

Stars
605
0.17% more than last month
Forks
50
Open Issues
23