toolkit.helpers.reports – custom reports helpers

toolkit.helpers.reports.csv_response(filename, table)

Return a CSV file of the given table as an HttpResponse.

Args:

filename: the name of the downloaded CSV file. The extension will be
‘.csv’. This parameter is inserted directly to the response’s Content-Disposition, and must be escaped accordingly.

table: a 2-dimensional iterable, in row-major order.

Returns:

A CSV HttpResponse with appropriate content_type and Content-Disposition.
toolkit.helpers.reports.generate_basic_table(columns, data)

Generate a table of functions applied to data objects.

Argument ‘columns’ is an iterable of 2-tuples of the form (title, function) where ‘title’ is the column title and ‘function’ is a single-parameter function that will be applied to each data element to create the column.

Returns a 2-dimensional row-major-ordered generator. The first row is the column titles; subsequent rows are evaluated functions of the data points.

Args:
columns: an iterable of pairs (title, function):
title: the string to appear at the top of the column. function: a callable to be applied to each datum in the column.
data: a QuerySet, list, or other iterable of arbitrary objects that can
be passed to the provided functions.
Yields:
rows of the table:
first row: the given column titles. subsequent rows: the given column functions applied to each datum.
Example usage:
>>> columns = [('Numbers', lambda x: x), ('Squares', lambda x: x ** 2)]
>>> data = [1, 2, 3, 4, 5]
>>> list(list(row) for row in generate_basic_table(columns, data))
[['Numbers', 'Squares'], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25]]
Author:
Fredrick Wagner
toolkit.helpers.reports.generate_table(columns, data, model=None, capitalize_title=True, remove_nones=False, **kwargs)

Wrapper around generate_basic_table with fancier column specifications.

Argument ‘columns’ is an iterable of specifications for table columns. Each specification is in one of three forms:

  • a tuple (title, func), where ‘title’ is the column title and ‘func’
    is a function that will be applied to each datum in the column. Specifications in this format will be passed through unchanged.
  • a tuple (title, attr). The column function will be a lookup of the
    provided attribute, which may be a model field, an ordinary object attribute, or a property.
  • a string, which is an attribute name as specified above. If the
    attribute is a model field and the ‘model’ arg is given, this column’s title will be the model’s verbose_name; otherwise, the title will be the string, with single and double underscores converted to single spaces.

See also getattr_chain, which this function uses to look up attributes given by the latter two types of column specifications. Any keyword args are passed through to it.

Args:

columns: an iterable of column specifications.

model: the model to look up field names from. Only used to get verbose
field names for column titles, and not used at all if all column specifications include titles.
capitalize_title: if True (the default), derived column names will have
their first letter capitalized.
remove_nones: if True, ‘None’ results from column functions will be
replaced with the empty string.

kwargs: passed through to function ‘getattr_chain’.

Yields:
Column specifications in the form (title, func).

Example:

def scholarship_report_view(request):
    table = generate_table([
        'id',
        'parent',
        ('Submission Date', 'submission_date'),
        ('Email Address', Scholarship.get_user_email),
        ('Random Numbers', lambda _: random.random()),
    ], data=Scholarship.objects.all(), model=Scholarship)
    return csv_response('Scholarship Information', table)

Author:

Fredrick Wagner
toolkit.helpers.reports.get_width(string, bold=False)

Assuming a standard 10-point Arial font, returns the width of the string, in BIFF column width units.

toolkit.helpers.reports.getattr_chain(obj, name_chain, suppress_attr_errors=False, sep='__')

Apply getattr successively to a chain of attribute names.

Argument ‘name_chain’ is a string containing sequence of attribute names to look up, starting with the initial object ‘obj’ and progressing through the chain. By default, a double underscore (‘__’) is expected to separate attribute names (as in Django’s admin config and queryset keyword args),but any string may be specified in argument ‘sep’. If ‘sep’ is None, argument ‘name_chain’ is instead expected to be an already-separated iterable of attribute names.

When evaluating a chain of attributes such as ‘foo__bar__baz’,in some cases ‘bar’ may sometimes be None, such as in database models with nullable foreign keys. In order to simplify the process of attempting to look up such values, argument ‘suppress_attr_errors’ may be given: if it is True, any AttributeErrors raised by lookups on None (e.g., ‘None.baz’) will be caught, and the value None will be returned instead. (Attempted lookups of invalid names will still raise errors as usual.) Be aware, though, that specifying this option will result in the same behavior whether ‘bar’ or ‘baz’ is None.

Note that while Django’s uses of such string-specified attribute lookups are limited to database relations, this function performs just as well with regular object attributes, and even with properties.

If a more complex lookup involving function calls or other logic is desired consider a lambda function, such as lambda obj: obj.foo.bar.baz.qux().

Args:

obj: the object start the attribute lookup from.

name_chain: a string containing a sequence of attribute names,separated
by the value of argument ‘sep’. May instead be an iterable of attribute names if ‘sep’ is None.
suppress_attr_errors: if True, catches AttributeErrors raised from an
attempted lookup on a None value anywhere in the attribute chain, and returns None instead of raising the exception.
sep: the delimiting characters between the consecutive attribute names
in argument ‘name_chain’. Default is ‘__’, but may be any string. If None, ‘name_chain’ is expected to be an iterable sequence of names, rather than a single string.
Returns:
The evaluation of the consecutive lookup of attributes in ‘name_chain’.

Example usage:

>>> class Obj(object): pass
>>> obj, obj.foo = Obj(), Obj()

>>> obj.foo.bar = None
>>> getattr_chain(obj, 'foo__bar')
>>> # None returned.
>>> getattr_chain(obj, 'foo__bar__baz')
Traceback (most recent call last):
    ...
AttributeError: 'NoneType' object has no attribute 'baz'
>>> getattr_chain(obj, 'foo__bar__baz', suppress_attr_errors=True)
>>> # None returned; no exception raised.

>>> obj.foo.bar = 'spam'
>>> getattr_chain(obj, 'foo__bar')
'spam'
>>> getattr_chain(obj, 'foo__bar__baz')
Traceback (most recent call last):
    ...
AttributeError: 'str' object has no attribute 'baz'
>>> getattr_chain(obj, 'foo__bar__baz', suppress_attr_errors=True)
Traceback (most recent call last):
    ...
AttributeError: 'str' object has no attribute 'baz'
>>> # Only AttributeErrors from NoneType are suppressed.
toolkit.helpers.reports.write_to_worksheet(ws, row, column, cell)

Write a single cell to a worksheet with xlwt. Used with xls_multiple_worksheets_response.

If “cell” is a dict and the key “merge” is present, the value of “merge” is also a dict with the potential to have keys called “row_span” and “col_span”. These parameters indicate what cells (starting at row, column) should be merged together.

Parameters:cell (str or dict with keys label, style and merge) – Simple or complex data to be written to the cell
toolkit.helpers.reports.xls_multiple_worksheets_response(filename, data, padding=0)

Take a filename and a dictionary (data) and return a .xls response that can have multiple sheets.

The user may indicate a style for a cell by passing in a dictionary with keys ‘label’ and ‘style’ instead of just a string.

The user may provide a header for each sheet. A header is a set of cells under the key “header” that appears first in the sheet.

data dict format:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
mystyle = 'font: bold 1'
data = {
    sheet_name: {
        'header': [
            ['cell 1:1', 'cell 1:2'],
            ['cell 2:1', {'label': 'cell 2:2', 'style': mystyle}]
        ],
        'table': [
            [{'label': 'cell 3:1', 'style': mystyle}, 'cell 3:2'],
            ['cell 4:1', 'cell 4:2']
        ]
    },
}

Styles are XFStyle strings. Comprehensive documentation for the format of these strings is difficult to find.

Brief example:
http://xlwt.readthedocs.org/en/latest/api.html#xlwt.Style.easyxf
Our example:
1
2
3
4
5
6
7
style = 'font: bold 1,
        'name Tahoma, ' \
        'height 160;' \
        'borders: left thick, right thick, top thick, ' \
        'bottom thick;  ' \
        'pattern: pattern solid, pattern_fore_colour  ' \
        'yellow,pattern_back_colour yellow'
toolkit.helpers.reports.xls_response(filename, sheetname, table, header=None, footer=None, include_totals=False, total_label='Total', grouper_col=None, value_col=None)

Return a Microsoft Excel file of the given table as an HttpResponse.

Args:

filename: the name of the downloaded file. The extension will be ‘.xls’
This parameter is inserted directly to the response’s Content-Disposition, and must be escaped accordingly.

sheetname: the name of the spreadsheet.

table: a 2-dimensional iterable, in row-major order.

header: an optional 2-dimensional iterable, in row-major order.

include_totals: an optional boolean to include total values.

total_label: Name of the total column, defaults to ‘Total’

grouper_col: Name of the group to subtotal values for (e.g. ‘Site’).

value_col: Name of the column which holds the values to be summed
(e.g.’Amount’).

Returns:

A Microsoft Excel HttpResponse with appropriate content_type and Content-Disposition.
toolkit.helpers.reports.xlsx_multiple_worksheets_response(filename, data, max_width=118, max_height=90)

Takes a filename and an ordered dictionary (data) and returns an .xlsx response that can have multiple worksheets.

data dict format:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
data = {
    sheet_name1: {
        'table': [
            ['cell 1:1', 'cell 1:2', 'cell 1:3'],  # This is often the header row
            ['cell 2:1', 'cell 2:2', 'cell 2:3'],
            ['cell 3:1', 'cell 3:2', 'cell 3:3'],
        ]
    },
    sheet_name2: {
        'table': [
            ['cell 1:1', 'cell 1:2'],
            ['cell 2:1', 'cell 2:2'],
            ['cell 3:1', 'cell 3:2'],
            ['cell 4:1', 'cell 4:2'],
        ]
    },
}
toolkit.helpers.reports.xlsx_response(filename, table, max_width=118, max_height=90)
Return a Microsoft Excel 2007+ file of the given table as an
HttpResponse.

Args:

filename: the name of the downloaded file. The extension will be ‘.xlsx’. This parameter is inserted directly to the response’s Content-Disposition, and must be escaped accordingly.

table: a 2-dimensional iterable, in row-major order.

Returns:

A Microsoft Excel 2007+ HttpResponse with appropriate content_type and Content-Disposition.