"admin_reports" is a Django application to easily create data aggregation reports to display inside Django admin.
The Django admin is very much centered on models and it provide a quick and simple way to create a GUI for the CRUD interface, but often there's the need to display data in an aggregate form, here's where admin_reports comes handy.
The idea is to have a class similar to ModelAdmin (from django.contrib.admin) that allow to display derived data concentrating on implementing the aggregation procedure.
Basically admin_reports provide your Django site with an abstract view Report. All you need to do is give an implementation to the abstract method aggregate(). The important thing is that this method must return a list of dictionaries, a Queryset or a pandas.Dataframe (https://github.com/pydata/pandas).
A stupid example could be this:
from admin_reports.reports import Report from admin_reports.decorators import register @register class MyReport(Report): def aggregate(self, **kwargs): return [ dict([(k, v) for v, k in enumerate('abcdefgh')]), dict([(k, v) for v, k in enumerate('abcdefgh')]), ] Then in your django site urls.py add the following:
from admin_reports import report_site urlpatterns = patterns( ... url(r'^reports/', include(report_site.urls)), ... )
The auto generate urls will be a lowercase, dash separated version of your class name.
So for the example above:
/reports/my-report
The Report class is projected to be flexible and let you modify various aspect of the final report.
As for the ModelAdmin the most straightforward way of changing the behavior of your subclasses is to override the public class attributes; anyway for each of these attributes there is a get_<attr> method hook to override in order to alter behaviors at run-time.
This is a list of field names that you want to be used as columns in your report, the default is None and means that the get_fields method will try to guess them from the results of your aggregate implementation.
The fields attribute can contain names of callables. This methods are supposed to receive a record of the report as a parameter.:
class MyReport(Report): fields = [ ..., 'pretty_value', ... ] def pretty_value(self, record): return do_something_fancy_with(record['my_column'])
For this callables the allow_tags attribute can be set to True if they are supposed to return an HTML string.
When a field name is provided alone in the fields attribute admin_reports will generate a label for you in the rendered table. If you want to provide a custom label just enter a tuple of two elements instead of just the field name, (field_name, label).
The formatting attribute is a dictionary that lets you specify the formatting function to use for each field.:
class MyReport(Report): formatting = { 'amount': lambda x: format(x, ',.2f'), } This attribute is a boolean to tell whether the last record of your aggregation is to be considered as a row of totals, in this case it will be displayed highlighted on every page.
Whether to display an eventual record of totals in on top of the table, if False it will be displayed on bottom.
This attribute has no effect if Report.has_totals is False.
A string to use as the page title.
A short description to explain the meaning of the report.
A longer description of the report, meant to explain the meaning of each single field.
The template to use to render the report as an html page (default: admin/report.html).
The class to use a Paginator.
list_per_page parameter passed to the Paginator class.
list_max_show_all parameter passed to the Paginator class.
How to align values in columns when rendering the html table, a dictionary that associates to each field one of the following values (aling-left, align-center, align-right).
The Form class to use to pass parameter to the aggregate method.
The Form class to use to pass parameter to the to_csv method.
Initial values for the form_class.