Skip to content

Introduction

While we were building the Cubed reporting dashboard, we always hit the same issue: how do you store static aggregated data for quick retrival but also have it being dynamic?

We wanted to be able to have users pull data from the DB but see it in different ways. You could achieve this by having a column for every metric and thus a table for every combination but this obviously gets out of hand instantly. If you have a field of "sales" you might want to show that as a sum() or even an avg() how about the min/max() of it?

How we dealt with this was by leveraging Django's Aggregate functions and building our own expressions. An expression would wrap the specific "field" in any math func/operator Django could offer. The next step was to build a generic way of utilising Django's annotate and aggregate functions - which are the foundations for building a sql group by statement.

This led us to building the CubedReportResource class which inherits from Tastypie's base ModelResource but then overrides a handful of functions to achieve what we want. Now any Django model we want to interact with and group by we inherit from CubedReportResource and then tell each field on the model/resource which expression they should use. We do this by using the install method found on the BaseFields class. Because we now know each field and the expression it will be using, we can add extra metrics to interact with them, this is done by the install_additional_metric . This function follows the exact same principals as install but will tell the resource (and thus Django) to "ignore this field" while validating the model and data. Both Tastypie and Django attempt to validate the fields on themselves - checking for types, indexes, and foreign keys.

We found that nearly all our report tables/classes were using the same default fields, and so we created BaseExpressions which would hold them. This class is initalized for every CubedReportResource, and can be added to by using the custom_expressions array. All fields can be overridden. If BaseExpressions has an expression for my_favourite_field and you add a new expression collections to custom_expressions which also has my_favourite_field, then that will be used when Django generates it's query.