def pivot(queryset, row, column, data, aggregation=Sum, choices='auto'): """ Takes a queryset and pivots it. The result is a table with one record per unique value in the `row` column, a column for each unique value in the `column` column and values in the table aggregated by the data column. :param queryset: a QuerySet, Model, or Manager :param row: string, name of column that will key the rows :param column: string, name of column that will define columns :param data: column name or Combinable :param aggregation: aggregation function to apply to data column :return: ValuesQueryset """ queryset = _get_queryset(queryset) column_values = get_column_values(queryset, column, choices) annotations = _get_annotations(column, column_values, data, aggregation) values = [row] row_choices = get_field_choices(queryset, row) if row_choices: whens = (When(Q(**{row: value}), then=Value(display_value, output_field=CharField())) for value, display_value in row_choices) row_display = Case(*whens) queryset = queryset.annotate( **{'get_' + row + '_display': row_display}) values.append('get_' + row + '_display') return queryset.values(*values).annotate(**annotations)
def pivot(queryset, rows, column, data, aggregation=Sum, choices='auto', display_transform=lambda s: s, default=None, row_range=()): """ Takes a queryset and pivots it. The result is a table with one record per unique value in the `row` column, a column for each unique value in the `column` column and values in the table aggregated by the data column. :param queryset: a QuerySet, Model, or Manager :param rows: list of strings, name of columns that will key the rows :param column: string, name of column that will define columns :param data: column name or Combinable :param aggregation: aggregation function to apply to data column :param display_transform: function that takes a string and returns a string :param default: default value to pass to the aggregate function when no record is found :param row_range: iterable with the expected range of rows in the result :return: ValuesQueryset """ values = [rows] if isinstance(rows, six.string_types) else list(rows) queryset = _get_queryset(queryset) column_values = get_column_values(queryset, column, choices) annotations = _get_annotations(column, column_values, data, aggregation, display_transform, default=default) for row in values: row_choices = get_field_choices(queryset, row) if row_choices: whens = (When(Q(**{row: value}), then=Value(display_value, output_field=CharField())) for value, display_value in row_choices) row_display = Case(*whens) queryset = queryset.annotate( **{'get_' + row + '_display': row_display}) values.append('get_' + row + '_display') values_list = queryset.values(*values).annotate(**annotations) if row_range: attributes = [value[0] for value in column_values] values_list = default_fill(values_list, values[0], row_range, fill_value=default, fill_attributes=attributes) return values_list