def _totals(values, layers, append=None): """ Get the totals of a row/column/report @param values: the values dictionary @param layers: the layers @param append: callback to collect the totals for JSON data (currently only collects the first layer) """ totals = [] for layer in layers: f, m = layer value = values[layer] if m == "list": value = value and len(value) or 0 if not len(totals) and append is not None: append(value) totals.append(IS_NUMBER.represent(value)) totals = " / ".join(totals) return totals
def __init__(self, report, show_totals=True, **attributes): """ Constructor @param report: the S3Pivottable instance @param attributes: the HTML attributes for the table """ T = current.T TOTAL = T("Total") TABLE.__init__(self, **attributes) components = self.components = [] self.json_data = None layers = report.layers resource = report.resource tablename = resource.tablename cols = report.cols rows = report.rows numcols = report.numcols numrows = report.numrows rfields = report.rfields get_label = self._get_label get_total = self._totals represent = lambda f, v, d="": \ self._represent(rfields, f, v, default=d) layer_label = None col_titles = [] add_col_title = col_titles.append col_totals = [] add_col_total = col_totals.append row_titles = [] add_row_title = row_titles.append row_totals = [] add_row_total = row_totals.append # Table header -------------------------------------------------------- # # Layer titles labels = [] get_mname = S3Report.mname for field_name, method in layers: label = get_label(rfields, field_name, tablename, "fact") mname = get_mname(method) if not labels: m = method == "list" and get_mname("count") or mname layer_label = "%s (%s)" % (label, m) labels.append("%s (%s)" % (label, mname)) layers_title = TH(" / ".join(labels)) # Columns field title if cols: col_label = get_label(rfields, cols, tablename, "cols") _colspan = numcols + 1 else: col_label = "" _colspan = numcols cols_title = TH(col_label, _colspan=_colspan, _scope="col") titles = TR(layers_title, cols_title) # Rows field title row_label = get_label(rfields, rows, tablename, "rows") rows_title = TH(row_label, _scope="col") headers = TR(rows_title) add_header = headers.append # Column headers values = report.col for i in xrange(numcols): value = values[i].value v = represent(cols, value) add_col_title(s3_truncate(unicode(v))) colhdr = TH(v, _scope="col") add_header(colhdr) # Row totals header if show_totals and cols is not None: add_header(TH(TOTAL, _class="totals_header rtotal", _scope="col")) thead = THEAD(titles, headers) # Table body ---------------------------------------------------------- # tbody = TBODY() add_row = tbody.append # lookup table for cell list values cell_lookup_table = {} # {{}, {}} cells = report.cell rvals = report.row for i in xrange(numrows): # Initialize row _class = i % 2 and "odd" or "even" tr = TR(_class=_class) add_cell = tr.append # Row header row = rvals[i] v = represent(rows, row.value) add_row_title(s3_truncate(unicode(v))) rowhdr = TD(v) add_cell(rowhdr) # Result cells for j in xrange(numcols): cell = cells[i][j] vals = [] cell_ids = [] add_value = vals.append for layer_idx, layer in enumerate(layers): f, m = layer value = cell[layer] if m == "list": if isinstance(value, list): l = [represent(f, v, d="-") for v in value] elif value is None: l = "-" else: if type(value) in (int, float): l = IS_NUMBER.represent(value) else: l = unicode(value) add_value(", ".join(l)) else: if type(value) in (int, float): add_value(IS_NUMBER.represent(value)) else: add_value(unicode(value)) # hold the references layer_ids = [] # get previous lookup values for this layer layer_values = cell_lookup_table.get(layer_idx, {}) if m == "count": rfield = rfields[f] field = rfield.field colname = rfield.colname has_fk = field is not None and s3_has_foreign_key(field) for id in cell.records: # cell.records == [#, #, #] record = report.records[id] try: fvalue = record[colname] except AttributeError: fvalue = None if fvalue is not None: if has_fk: if not isinstance(fvalue, list): fvalue = [fvalue] # list of foreign keys for fk in fvalue: if fk not in layer_ids: layer_ids.append(fk) layer_values[fk] = str(field.represent(fk)) else: if id not in layer_ids: layer_ids.append(id) layer_values[id] = s3_unicode(represent(f, fvalue)) cell_ids.append(layer_ids) cell_lookup_table[layer_idx] = layer_values vals = " / ".join(vals) if any(cell_ids): cell_attr = { "_data-records": cell_ids } vals = (A(_class="report-cell-zoom"), vals) else: cell_attr = {} add_cell(TD(vals, **cell_attr)) # Row total totals = get_total(row, layers, append=add_row_total) if show_totals and cols is not None: add_cell(TD(totals)) add_row(tr) # Table footer -------------------------------------------------------- # i = numrows _class = i % 2 and "odd" or "even" _class = "%s %s" % (_class, "totals_row") col_total = TR(_class=_class) add_total = col_total.append add_total(TH(TOTAL, _class="totals_header", _scope="row")) # Column totals for j in xrange(numcols): col = report.col[j] totals = get_total(col, layers, append=add_col_total) add_total(TD(IS_NUMBER.represent(totals))) # Grand total if cols is not None: grand_totals = get_total(report.totals, layers) add_total(TD(grand_totals)) tfoot = TFOOT(col_total) # Wrap up ------------------------------------------------------------- # append = components.append append(thead) append(tbody) if show_totals: append(tfoot) # Chart data ---------------------------------------------------------- # drows = dcols = None BY = T("by") top = self._top if rows and row_titles and row_totals: drows = top(zip(row_titles, row_totals)) if cols and col_titles and col_totals: dcols = top(zip(col_titles, col_totals)) row_label = "%s %s" % (BY, str(row_label)) if col_label: col_label = "%s %s" % (BY, str(col_label)) layer_label=str(layer_label) json_data = json.dumps(dict(rows=drows, cols=dcols, data=report.compact(10, represent=True), row_label=row_label, col_label=col_label, layer_label=layer_label, cell_lookup_table=cell_lookup_table )) self.report_data = Storage(row_label=row_label, col_label=col_label, layer_label=layer_label, json_data=json_data)
def __init__(self, report, show_totals=True, url=None, filter_query=None, **attributes): """ Constructor @param report: the S3Pivottable instance @param attributes: the HTML attributes for the table """ T = current.T TOTAL = T("Total") TABLE.__init__(self, **attributes) components = self.components = [] self.json_data = None layers = report.layers resource = report.resource tablename = resource.tablename cols = report.cols rows = report.rows numcols = report.numcols numrows = report.numrows rfields = report.rfields get_label = self._get_label get_total = self._totals represent = lambda f, v, d="": \ self._represent(rfields, f, v, default=d) layer_label = None col_titles = [] add_col_title = col_titles.append col_totals = [] add_col_total = col_totals.append row_titles = [] add_row_title = row_titles.append row_totals = [] add_row_total = row_totals.append # Layer titles -------------------------------------------------------- # Get custom labels from report options layer_labels = Storage() report_options = resource.get_config("report_options", None) if report_options and "fact" in report_options: layer_opts = report_options["fact"] for item in layer_opts: if isinstance(item, (tuple, list)) and len(item) == 3: if not "." in item[0].split("$")[0]: item = ("%s.%s" % (resource.alias, item[0]), item[1], item[2]) layer_labels[(item[0], item[1])] = item[2] labels = [] get_mname = S3Report.mname for layer in layers: if layer in layer_labels: # Custom label label = layer_labels[layer] if not labels: layer_label = label labels.append(s3_unicode(label)) else: # Construct label from field-label and method label = get_label(rfields, layer[0], tablename, "fact") mname = get_mname(layer[1]) if not labels: m = layer[1] == "list" and get_mname("count") or mname layer_label = "%s (%s)" % (label, m) labels.append("%s (%s)" % (label, mname)) layers_title = TH(" / ".join(labels)) # Columns field title ------------------------------------------------- if cols: col_label = get_label(rfields, cols, tablename, "cols") _colspan = numcols + 1 else: col_label = "" _colspan = numcols cols_title = TH(col_label, _colspan=_colspan, _scope="col") titles = TR(layers_title, cols_title) # Rows field title ---------------------------------------------------- row_label = get_label(rfields, rows, tablename, "rows") rows_title = TH(row_label, _scope="col") headers = TR(rows_title) # Column headers ------------------------------------------------------ add_header = headers.append values = report.col for i in xrange(numcols): value = values[i].value v = represent(cols, value) add_col_title(s3_truncate(unicode(v))) colhdr = TH(v, _scope="col") add_header(colhdr) # Row totals header --------------------------------------------------- if show_totals and cols is not None: add_header(TH(TOTAL, _class="totals_header rtotal", _scope="col")) thead = THEAD(titles, headers) # Table body ---------------------------------------------------------- tbody = TBODY() add_row = tbody.append # lookup table for cell list values cell_lookup_table = {} # {{}, {}} cells = report.cell rvals = report.row cell_vals = Storage() for i in xrange(numrows): # Initialize row _class = i % 2 and "odd" or "even" tr = TR(_class=_class) add_cell = tr.append # Row header row = rvals[i] v = represent(rows, row.value) add_row_title(s3_truncate(unicode(v))) rowhdr = TD(v) add_cell(rowhdr) # Result cells for j in xrange(numcols): cell = cells[i][j] vals = [] cell_ids = [] add_value = vals.append for layer_idx, layer in enumerate(layers): f, m = layer value = cell[layer] if m == "list": if isinstance(value, list): l = [represent(f, v, d="-") for v in value] elif value is None: l = ["-"] else: if type(value) in (int, float): l = IS_NUMBER.represent(value) else: l = unicode(value) #add_value(", ".join(l)) add_value(UL([LI(v) for v in l])) else: if type(value) in (int, float): add_value(IS_NUMBER.represent(value)) else: add_value(unicode(value)) # hold the references layer_ids = [] # get previous lookup values for this layer layer_values = cell_lookup_table.get(layer_idx, {}) if m == "count": rfield = rfields[f] field = rfield.field colname = rfield.colname has_fk = field is not None and s3_has_foreign_key(field) for id in cell.records: # cell.records == [#, #, #] record = report.records[id] try: fvalue = record[colname] except AttributeError: fvalue = None if fvalue is not None: if has_fk: if type(fvalue) is not list: fvalue = [fvalue] # list of foreign keys for fk in fvalue: if fk is not None and fk not in layer_ids: layer_ids.append(int(fk)) layer_values[fk] = s3_unicode(field.represent(fk)) else: if type(fvalue) is not list: fvalue = [fvalue] for val in fvalue: if val is not None: if val not in cell_vals: next_id = len(cell_vals) cell_vals[val] = next_id layer_ids.append(next_id) layer_values[next_id] = s3_unicode(represent(f, val)) else: prev_id = cell_vals[val] if prev_id not in layer_ids: layer_ids.append(prev_id) #if id is not None and id not in layer_ids: #layer_ids.append(int(id)) #layer_values[id] = s3_unicode(represent(f, fvalue)) cell_ids.append(layer_ids) cell_lookup_table[layer_idx] = layer_values # @todo: with multiple layers - show the first, hide the rest # + render layer selector in the layer title corner to # + switch between layers # OR: give every layer a title row (probably better method) vals = [DIV(v, _class="report-cell-value") for v in vals] if any(cell_ids): cell_attr = {"_data-records": cell_ids} vals.append(DIV(_class="report-cell-zoom")) else: cell_attr = {} add_cell(TD(vals, **cell_attr)) # Row total totals = get_total(row, layers, append=add_row_total) if show_totals and cols is not None: add_cell(TD(totals)) add_row(tr) # Table footer -------------------------------------------------------- i = numrows _class = i % 2 and "odd" or "even" _class = "%s %s" % (_class, "totals_row") col_total = TR(_class=_class) add_total = col_total.append add_total(TH(TOTAL, _class="totals_header", _scope="row")) # Column totals ------------------------------------------------------- for j in xrange(numcols): col = report.col[j] totals = get_total(col, layers, append=add_col_total) add_total(TD(IS_NUMBER.represent(totals))) # Grand total --------------------------------------------------------- if cols is not None: grand_totals = get_total(report.totals, layers) add_total(TD(grand_totals)) tfoot = TFOOT(col_total) # Wrap up ------------------------------------------------------------- append = components.append append(thead) append(tbody) if show_totals: append(tfoot) # Chart data ---------------------------------------------------------- layer_label = s3_unicode(layer_label) BY = T("by") row_label = "%s %s" % (BY, s3_unicode(row_label)) if col_label: col_label = "%s %s" % (BY, s3_unicode(col_label)) if filter_query and hasattr(filter_query, "serialize_url"): filter_vars = filter_query.serialize_url(resource=report.resource) else: filter_vars = {} hide_opts = current.deployment_settings.get_ui_hide_report_options() json_data = json.dumps(dict(t=layer_label, x=col_label, y=row_label, r=report.rows, c=report.cols, d=report.compact(n=50, represent=True), u=url, f=filter_vars, h=hide_opts, cell_lookup_table=cell_lookup_table)) self.report_data = Storage(row_label=row_label, col_label=col_label, layer_label=layer_label, json_data=json_data)
def __init__(self, report, show_totals=True, url=None, filter_query=None, **attributes): """ Constructor @param report: the S3Pivottable instance @param show_totals: show totals for rows and columns @param url: link cells to this base-URL @param filter_query: use this S3ResourceQuery with the base-URL @param attributes: the HTML attributes for the table """ T = current.T TOTAL = T("Total") TABLE.__init__(self, **attributes) components = self.components = [] self.json_data = None layers = report.layers resource = report.resource tablename = resource.tablename cols = report.cols rows = report.rows numcols = report.numcols numrows = report.numrows rfields = report.rfields get_label = self._get_label get_total = self._totals represent = lambda f, v, d="": \ self._represent(rfields, f, v, default=d) layer_label = None col_titles = [] add_col_title = col_titles.append col_totals = [] add_col_total = col_totals.append row_titles = [] add_row_title = row_titles.append row_totals = [] add_row_total = row_totals.append # Layer titles: # Get custom labels from report options layer_labels = Storage() report_options = resource.get_config("report_options", None) if report_options and "fact" in report_options: layer_opts = report_options["fact"] for item in layer_opts: if isinstance(item, (tuple, list)) and len(item) == 3: if not "." in item[0].split("$")[0]: item = ("%s.%s" % (resource.alias, item[0]), item[1], item[2]) layer_labels[(item[0], item[1])] = item[2] labels = [] get_mname = S3Report.mname for layer in layers: if layer in layer_labels: # Custom label label = layer_labels[layer] if not labels: layer_label = label labels.append(s3_unicode(label)) else: # Construct label from field-label and method label = get_label(rfields, layer[0], tablename, "fact") mname = get_mname(layer[1]) if not labels: m = layer[1] == "list" and get_mname("count") or mname layer_label = "%s (%s)" % (label, m) labels.append("%s (%s)" % (label, mname)) layers_title = TH(" / ".join(labels)) # Columns field title if cols: col_label = get_label(rfields, cols, tablename, "cols") _colspan = numcols + 1 else: col_label = "" _colspan = numcols cols_title = TH(col_label, _colspan=_colspan, _scope="col") titles = TR(layers_title, cols_title) # Sort dimensions: cells = report.cell def sortdim(dim, items): """ Sort a dimension """ rfield = rfields[dim] if not rfield: return ftype = rfield.ftype sortby = "value" if ftype == "integer": requires = rfield.requires if isinstance(requires, (tuple, list)): requires = requires[0] if isinstance(requires, IS_EMPTY_OR): requires = requires.other if isinstance(requires, IS_IN_SET): sortby = "text" elif ftype[:9] == "reference": sortby = "text" items.sort(key=lambda item: item[0][sortby]) # Sort rows rvals = report.row rows_list = [] for i in xrange(numrows): row = rvals[i] # Add representation value of the row header row["text"] = represent(rows, row.value) rows_list.append((row, cells[i])) sortdim(rows, rows_list) # Sort columns cvals = report.col cols_list = [] for j in xrange(numcols): column = cvals[j] column["text"] = represent(cols, column.value) cols_list.append((column, j)) sortdim(cols, cols_list) # Build the column headers: # Header for the row-titles column row_label = get_label(rfields, rows, tablename, "rows") rows_title = TH(row_label, _scope="col") headers = TR(rows_title) add_header = headers.append # Headers for the cell columns for j in xrange(numcols): v = cols_list[j][0].text add_col_title(s3_truncate(unicode(v))) colhdr = TH(v, _scope="col") add_header(colhdr) # Header for the row-totals column if show_totals and cols is not None: add_header(TH(TOTAL, _class="totals_header rtotal", _scope="col")) thead = THEAD(titles, headers) # Render the table body: tbody = TBODY() add_row = tbody.append # Lookup table for cell list values cell_lookup_table = {} # {{}, {}} cell_vals = Storage() for i in xrange(numrows): # Initialize row _class = i % 2 and "odd" or "even" tr = TR(_class=_class) add_cell = tr.append # Row header row = rows_list[i][0] v = row["text"] add_row_title(s3_truncate(unicode(v))) rowhdr = TD(v) add_cell(rowhdr) row_cells = rows_list[i][1] # Result cells for j in xrange(numcols): cell_idx = cols_list[j][1] cell = row_cells[cell_idx] vals = [] cell_ids = [] add_value = vals.append for layer_idx, layer in enumerate(layers): f, m = layer value = cell[layer] if m == "list": if isinstance(value, list): l = [represent(f, v, d="-") for v in value] elif value is None: l = ["-"] else: if type(value) in (int, float): l = IS_NUMBER.represent(value) else: l = unicode(value) #add_value(", ".join(l)) add_value(UL([LI(v) for v in l])) else: if type(value) in (int, float): add_value(IS_NUMBER.represent(value)) else: add_value(unicode(value)) layer_ids = [] layer_values = cell_lookup_table.get(layer_idx, {}) if m == "count": rfield = rfields[f] field = rfield.field colname = rfield.colname has_fk = field is not None and s3_has_foreign_key( field) for id in cell.records: record = report.records[id] try: fvalue = record[colname] except AttributeError: fvalue = None if fvalue is not None: if has_fk: if type(fvalue) is not list: fvalue = [fvalue] # list of foreign keys for fk in fvalue: if fk is not None and fk not in layer_ids: layer_ids.append(int(fk)) layer_values[fk] = s3_unicode( field.represent(fk)) else: if type(fvalue) is not list: fvalue = [fvalue] for val in fvalue: if val is not None: if val not in cell_vals: next_id = len(cell_vals) cell_vals[val] = next_id layer_ids.append(next_id) layer_values[ next_id] = s3_unicode( represent(f, val)) else: prev_id = cell_vals[val] if prev_id not in layer_ids: layer_ids.append(prev_id) cell_ids.append(layer_ids) cell_lookup_table[layer_idx] = layer_values vals = [DIV(v, _class="report-cell-value") for v in vals] if any(cell_ids): cell_attr = {"_data-records": cell_ids} vals.append(DIV(_class="report-cell-zoom")) else: cell_attr = {} add_cell(TD(vals, **cell_attr)) # Row total totals = get_total(row, layers, append=add_row_total) if show_totals and cols is not None: add_cell(TD(totals)) add_row(tr) # Table footer: i = numrows _class = i % 2 and "odd" or "even" _class = "%s %s" % (_class, "totals_row") col_total = TR(_class=_class) add_total = col_total.append add_total(TH(TOTAL, _class="totals_header", _scope="row")) # Column totals for j in xrange(numcols): cell_idx = cols_list[j][1] col = report.col[cell_idx] totals = get_total(col, layers, append=add_col_total) add_total(TD(IS_NUMBER.represent(totals))) # Grand total if cols is not None: grand_totals = get_total(report.totals, layers) add_total(TD(grand_totals)) tfoot = TFOOT(col_total) # Wrap up: append = components.append append(thead) append(tbody) if show_totals: append(tfoot) # Chart data: layer_label = s3_unicode(layer_label) BY = T("by") row_label = "%s %s" % (BY, s3_unicode(row_label)) if col_label: col_label = "%s %s" % (BY, s3_unicode(col_label)) if filter_query and hasattr(filter_query, "serialize_url"): filter_vars = filter_query.serialize_url(resource=report.resource) else: filter_vars = {} hide_opts = current.deployment_settings.get_ui_hide_report_options() json_data = json.dumps( dict(t=layer_label, x=col_label, y=row_label, r=report.rows, c=report.cols, d=report.compact(n=50, represent=True), u=url, f=filter_vars, h=hide_opts, cell_lookup_table=cell_lookup_table)) self.report_data = Storage(row_label=row_label, col_label=col_label, layer_label=layer_label, json_data=json_data)
def __init__(self, report, show_totals=True, url=None, filter_query=None, **attributes): """ Constructor @param report: the S3Pivottable instance @param show_totals: show totals for rows and columns @param url: link cells to this base-URL @param filter_query: use this S3ResourceQuery with the base-URL @param attributes: the HTML attributes for the table """ T = current.T TOTAL = T("Total") TABLE.__init__(self, **attributes) components = self.components = [] self.json_data = None layers = report.layers resource = report.resource tablename = resource.tablename cols = report.cols rows = report.rows numcols = report.numcols numrows = report.numrows rfields = report.rfields get_label = self._get_label get_total = self._totals represent = lambda f, v, d="": \ self._represent(rfields, f, v, default=d) layer_label = None col_titles = [] add_col_title = col_titles.append col_totals = [] add_col_total = col_totals.append row_titles = [] add_row_title = row_titles.append row_totals = [] add_row_total = row_totals.append # Layer titles: # Get custom labels from report options layer_labels = Storage() report_options = resource.get_config("report_options", None) if report_options and "fact" in report_options: layer_opts = report_options["fact"] for item in layer_opts: if isinstance(item, (tuple, list)) and len(item) == 3: if not "." in item[0].split("$")[0]: item = ("%s.%s" % (resource.alias, item[0]), item[1], item[2]) layer_labels[(item[0], item[1])] = item[2] labels = [] get_mname = S3Report.mname for layer in layers: if layer in layer_labels: # Custom label label = layer_labels[layer] if not labels: layer_label = label labels.append(s3_unicode(label)) else: # Construct label from field-label and method label = get_label(rfields, layer[0], tablename, "fact") mname = get_mname(layer[1]) if not labels: m = layer[1] == "list" and get_mname("count") or mname layer_label = "%s (%s)" % (label, m) labels.append("%s (%s)" % (label, mname)) layers_title = TH(" / ".join(labels)) # Columns field title if cols: col_label = get_label(rfields, cols, tablename, "cols") _colspan = numcols + 1 else: col_label = "" _colspan = numcols cols_title = TH(col_label, _colspan=_colspan, _scope="col") titles = TR(layers_title, cols_title) # Sort dimensions: cells = report.cell def sortdim(dim, items): """ Sort a dimension """ rfield = rfields[dim] if not rfield: return ftype = rfield.ftype sortby = "value" if ftype == "integer": requires = rfield.requires if isinstance(requires, (tuple, list)): requires = requires[0] if isinstance(requires, IS_EMPTY_OR): requires = requires.other if isinstance(requires, IS_IN_SET): sortby = "text" elif ftype[:9] == "reference": sortby = "text" items.sort(key=lambda item: item[0][sortby]) # Sort rows rvals = report.row rows_list = [] for i in xrange(numrows): row = rvals[i] # Add representation value of the row header row["text"] = represent(rows, row.value) rows_list.append((row, cells[i])) sortdim(rows, rows_list) # Sort columns cvals = report.col cols_list = [] for j in xrange(numcols): column = cvals[j] column["text"] = represent(cols, column.value) cols_list.append((column, j)) sortdim(cols, cols_list) # Build the column headers: # Header for the row-titles column row_label = get_label(rfields, rows, tablename, "rows") rows_title = TH(row_label, _scope="col") headers = TR(rows_title) add_header = headers.append # Headers for the cell columns for j in xrange(numcols): v = cols_list[j][0].text add_col_title(s3_truncate(unicode(v))) colhdr = TH(v, _scope="col") add_header(colhdr) # Header for the row-totals column if show_totals and cols is not None: add_header(TH(TOTAL, _class="totals_header rtotal", _scope="col")) thead = THEAD(titles, headers) # Render the table body: tbody = TBODY() add_row = tbody.append # Lookup table for cell list values cell_lookup_table = {} # {{}, {}} cell_vals = Storage() for i in xrange(numrows): # Initialize row _class = i % 2 and "odd" or "even" tr = TR(_class=_class) add_cell = tr.append # Row header row = rows_list[i][0] v = row["text"] add_row_title(s3_truncate(unicode(v))) rowhdr = TD(v) add_cell(rowhdr) row_cells = rows_list[i][1] # Result cells for j in xrange(numcols): cell_idx = cols_list[j][1] cell = row_cells[cell_idx] vals = [] cell_ids = [] add_value = vals.append for layer_idx, layer in enumerate(layers): f, m = layer value = cell[layer] if m == "list": if isinstance(value, list): l = [represent(f, v, d="-") for v in value] elif value is None: l = ["-"] else: if type(value) in (int, float): l = IS_NUMBER.represent(value) else: l = unicode(value) #add_value(", ".join(l)) add_value(UL([LI(v) for v in l])) else: if type(value) in (int, float): add_value(IS_NUMBER.represent(value)) else: add_value(unicode(value)) layer_ids = [] layer_values = cell_lookup_table.get(layer_idx, {}) if m == "count": rfield = rfields[f] field = rfield.field colname = rfield.colname has_fk = field is not None and s3_has_foreign_key(field) for id in cell.records: record = report.records[id] try: fvalue = record[colname] except AttributeError: fvalue = None if fvalue is not None: if has_fk: if type(fvalue) is not list: fvalue = [fvalue] # list of foreign keys for fk in fvalue: if fk is not None and fk not in layer_ids: layer_ids.append(int(fk)) layer_values[fk] = s3_unicode(field.represent(fk)) else: if type(fvalue) is not list: fvalue = [fvalue] for val in fvalue: if val is not None: if val not in cell_vals: next_id = len(cell_vals) cell_vals[val] = next_id layer_ids.append(next_id) layer_values[next_id] = s3_unicode(represent(f, val)) else: prev_id = cell_vals[val] if prev_id not in layer_ids: layer_ids.append(prev_id) cell_ids.append(layer_ids) cell_lookup_table[layer_idx] = layer_values vals = [DIV(v, _class="report-cell-value") for v in vals] if any(cell_ids): cell_attr = {"_data-records": cell_ids} vals.append(DIV(_class="report-cell-zoom")) else: cell_attr = {} add_cell(TD(vals, **cell_attr)) # Row total totals = get_total(row, layers, append=add_row_total) if show_totals and cols is not None: add_cell(TD(totals)) add_row(tr) # Table footer: i = numrows _class = i % 2 and "odd" or "even" _class = "%s %s" % (_class, "totals_row") col_total = TR(_class=_class) add_total = col_total.append add_total(TH(TOTAL, _class="totals_header", _scope="row")) # Column totals for j in xrange(numcols): cell_idx = cols_list[j][1] col = report.col[cell_idx] totals = get_total(col, layers, append=add_col_total) add_total(TD(IS_NUMBER.represent(totals))) # Grand total if cols is not None: grand_totals = get_total(report.totals, layers) add_total(TD(grand_totals)) tfoot = TFOOT(col_total) # Wrap up: append = components.append append(thead) append(tbody) if show_totals: append(tfoot) # Chart data: layer_label = s3_unicode(layer_label) BY = T("by") row_label = "%s %s" % (BY, s3_unicode(row_label)) if col_label: col_label = "%s %s" % (BY, s3_unicode(col_label)) if filter_query and hasattr(filter_query, "serialize_url"): filter_vars = filter_query.serialize_url(resource=report.resource) else: filter_vars = {} hide_opts = current.deployment_settings.get_ui_hide_report_options() json_data = json.dumps(dict(t=layer_label, x=col_label, y=row_label, r=report.rows, c=report.cols, d=report.compact(n=50, represent=True), u=url, f=filter_vars, h=hide_opts, cell_lookup_table=cell_lookup_table)) self.report_data = Storage(row_label=row_label, col_label=col_label, layer_label=layer_label, json_data=json_data)
def __init__(self, report, show_totals=True, **attributes): """ Constructor @param report: the S3Pivottable instance @param attributes: the HTML attributes for the table """ T = current.T TOTAL = T("Total") TABLE.__init__(self, **attributes) components = self.components = [] self.json_data = None layers = report.layers resource = report.resource tablename = resource.tablename cols = report.cols rows = report.rows numcols = report.numcols numrows = report.numrows rfields = report.rfields get_label = self._get_label get_total = self._totals represent = lambda f, v, d="": \ self._represent(rfields, f, v, default=d) layer_label = None col_titles = [] add_col_title = col_titles.append col_totals = [] add_col_total = col_totals.append row_titles = [] add_row_title = row_titles.append row_totals = [] add_row_total = row_totals.append # Table header -------------------------------------------------------- # # Layer titles labels = [] get_mname = S3Report.mname for field_name, method in layers: label = get_label(rfields, field_name, tablename, "fact") mname = get_mname(method) if not labels: m = method == "list" and get_mname("count") or mname layer_label = "%s (%s)" % (label, m) labels.append("%s (%s)" % (label, mname)) layers_title = TH(" / ".join(labels)) # Columns field title if cols: col_label = get_label(rfields, cols, tablename, "cols") _colspan = numcols + 1 else: col_label = "" _colspan = numcols cols_title = TH(col_label, _colspan=_colspan, _scope="col") titles = TR(layers_title, cols_title) # Rows field title row_label = get_label(rfields, rows, tablename, "rows") rows_title = TH(row_label, _scope="col") headers = TR(rows_title) add_header = headers.append # Column headers values = report.col for i in xrange(numcols): value = values[i].value v = represent(cols, value) add_col_title(s3_truncate(unicode(v))) colhdr = TH(v, _scope="col") add_header(colhdr) # Row totals header if show_totals and cols is not None: add_header(TH(TOTAL, _class="totals_header rtotal", _scope="col")) thead = THEAD(titles, headers) # Table body ---------------------------------------------------------- # tbody = TBODY() add_row = tbody.append # lookup table for cell list values cell_lookup_table = {} # {{}, {}} cells = report.cell rvals = report.row for i in xrange(numrows): # Initialize row _class = i % 2 and "odd" or "even" tr = TR(_class=_class) add_cell = tr.append # Row header row = rvals[i] v = represent(rows, row.value) add_row_title(s3_truncate(unicode(v))) rowhdr = TD(v) add_cell(rowhdr) # Result cells for j in xrange(numcols): cell = cells[i][j] vals = [] cell_ids = [] add_value = vals.append for layer_idx, layer in enumerate(layers): f, m = layer value = cell[layer] if m == "list": if isinstance(value, list): l = [represent(f, v, d="-") for v in value] elif value is None: l = "-" else: if type(value) in (int, float): l = IS_NUMBER.represent(value) else: l = unicode(value) add_value(", ".join(l)) else: if type(value) in (int, float): add_value(IS_NUMBER.represent(value)) else: add_value(unicode(value)) # hold the references layer_ids = [] # get previous lookup values for this layer layer_values = cell_lookup_table.get(layer_idx, {}) if m == "count": for id in cell.records: # cell.records == [#, #, #] field = rfields[f].field record = report.records[id] if field.tablename in record: fvalue = record[field.tablename][field.name] else: fvalue = record[field.name] if fvalue is not None: if s3_has_foreign_key(field): if not isinstance(fvalue, list): fvalue = [fvalue] # list of foreign keys for fk in fvalue: if fk not in layer_ids: layer_ids.append(fk) layer_values[fk] = str(field.represent(fk)) else: if id not in layer_ids: layer_ids.append(id) layer_values[id] = s3_unicode(represent(f, fvalue)) cell_ids.append(layer_ids) cell_lookup_table[layer_idx] = layer_values vals = " / ".join(vals) if any(cell_ids): cell_attr = { "_data-records": cell_ids } vals = (A(_class="report-cell-zoom"), vals) else: cell_attr = {} add_cell(TD(vals, **cell_attr)) # Row total totals = get_total(row, layers, append=add_row_total) if show_totals and cols is not None: add_cell(TD(totals)) add_row(tr) # Table footer -------------------------------------------------------- # i = numrows _class = i % 2 and "odd" or "even" _class = "%s %s" % (_class, "totals_row") col_total = TR(_class=_class) add_total = col_total.append add_total(TH(TOTAL, _class="totals_header", _scope="row")) # Column totals for j in xrange(numcols): col = report.col[j] totals = get_total(col, layers, append=add_col_total) add_total(TD(IS_NUMBER.represent(totals))) # Grand total if cols is not None: grand_totals = get_total(report.totals, layers) add_total(TD(grand_totals)) tfoot = TFOOT(col_total) # Wrap up ------------------------------------------------------------- # append = components.append append(thead) append(tbody) if show_totals: append(tfoot) # Chart data ---------------------------------------------------------- # drows = dcols = None BY = T("by") top = self._top if rows and row_titles and row_totals: drows = top(zip(row_titles, row_totals)) if cols and col_titles and col_totals: dcols = top(zip(col_titles, col_totals)) row_label = "%s %s" % (BY, str(row_label)) if col_label: col_label = "%s %s" % (BY, str(col_label)) layer_label=str(layer_label) json_data = json.dumps(dict(rows=drows, cols=dcols, row_label=row_label, col_label=col_label, layer_label=layer_label, cell_lookup_table=cell_lookup_table )) self.report_data = Storage(row_label=row_label, col_label=col_label, layer_label=layer_label, json_data=json_data)
def __init__(self, report, show_totals=True, url=None, filter_query=None, **attributes): """ Constructor @param report: the S3Pivottable instance @param attributes: the HTML attributes for the table """ T = current.T TOTAL = T("Total") TABLE.__init__(self, **attributes) components = self.components = [] self.json_data = None layers = report.layers resource = report.resource tablename = resource.tablename cols = report.cols rows = report.rows numcols = report.numcols numrows = report.numrows rfields = report.rfields get_label = self._get_label get_total = self._totals represent = lambda f, v, d="": \ self._represent(rfields, f, v, default=d) layer_label = None col_titles = [] add_col_title = col_titles.append col_totals = [] add_col_total = col_totals.append row_titles = [] add_row_title = row_titles.append row_totals = [] add_row_total = row_totals.append # Layer titles -------------------------------------------------------- labels = [] get_mname = S3Report.mname for field_name, method in layers: # @todo: get the layer label from the report options label = get_label(rfields, field_name, tablename, "fact") mname = get_mname(method) if not labels: m = method == "list" and get_mname("count") or mname layer_label = "%s (%s)" % (label, m) labels.append("%s (%s)" % (label, mname)) layers_title = TH(" / ".join(labels)) # Columns field title ------------------------------------------------- if cols: col_label = get_label(rfields, cols, tablename, "cols") _colspan = numcols + 1 else: col_label = "" _colspan = numcols cols_title = TH(col_label, _colspan=_colspan, _scope="col") titles = TR(layers_title, cols_title) # Rows field title ---------------------------------------------------- row_label = get_label(rfields, rows, tablename, "rows") rows_title = TH(row_label, _scope="col") headers = TR(rows_title) # Column headers ------------------------------------------------------ add_header = headers.append values = report.col for i in xrange(numcols): value = values[i].value v = represent(cols, value) add_col_title(s3_truncate(unicode(v))) colhdr = TH(v, _scope="col") add_header(colhdr) # Row totals header --------------------------------------------------- if show_totals and cols is not None: add_header(TH(TOTAL, _class="totals_header rtotal", _scope="col")) thead = THEAD(titles, headers) # Table body ---------------------------------------------------------- tbody = TBODY() add_row = tbody.append # lookup table for cell list values cell_lookup_table = {} # {{}, {}} cells = report.cell rvals = report.row for i in xrange(numrows): # Initialize row _class = i % 2 and "odd" or "even" tr = TR(_class=_class) add_cell = tr.append # Row header row = rvals[i] v = represent(rows, row.value) add_row_title(s3_truncate(unicode(v))) rowhdr = TD(v) add_cell(rowhdr) # Result cells for j in xrange(numcols): cell = cells[i][j] vals = [] cell_ids = [] add_value = vals.append for layer_idx, layer in enumerate(layers): f, m = layer value = cell[layer] if m == "list": if isinstance(value, list): l = [represent(f, v, d="-") for v in value] elif value is None: l = ["-"] else: if type(value) in (int, float): l = IS_NUMBER.represent(value) else: l = unicode(value) #add_value(", ".join(l)) add_value(UL([LI(v) for v in l])) else: if type(value) in (int, float): add_value(IS_NUMBER.represent(value)) else: add_value(unicode(value)) # hold the references layer_ids = [] # get previous lookup values for this layer layer_values = cell_lookup_table.get(layer_idx, {}) if m == "count": rfield = rfields[f] field = rfield.field colname = rfield.colname has_fk = field is not None and s3_has_foreign_key( field) for id in cell.records: # cell.records == [#, #, #] record = report.records[id] try: fvalue = record[colname] except AttributeError: fvalue = None if fvalue is not None: if has_fk: if not isinstance(fvalue, list): fvalue = [fvalue] # list of foreign keys for fk in fvalue: if fk not in layer_ids: layer_ids.append(fk) layer_values[fk] = str( field.represent(fk)) else: if id not in layer_ids: layer_ids.append(id) layer_values[id] = s3_unicode( represent(f, fvalue)) cell_ids.append(layer_ids) cell_lookup_table[layer_idx] = layer_values # @todo: with multiple layers - show the first, hide the rest # + render layer selector in the layer title corner to # + switch between layers # OR: give every layer a title row (probably better method) vals = DIV([DIV(v) for v in vals]) if any(cell_ids): cell_attr = {"_data-records": cell_ids} vals = (A(_class="report-cell-zoom"), vals) else: cell_attr = {} add_cell(TD(vals, **cell_attr)) # Row total totals = get_total(row, layers, append=add_row_total) if show_totals and cols is not None: add_cell(TD(totals)) add_row(tr) # Table footer -------------------------------------------------------- i = numrows _class = i % 2 and "odd" or "even" _class = "%s %s" % (_class, "totals_row") col_total = TR(_class=_class) add_total = col_total.append add_total(TH(TOTAL, _class="totals_header", _scope="row")) # Column totals ------------------------------------------------------- for j in xrange(numcols): col = report.col[j] totals = get_total(col, layers, append=add_col_total) add_total(TD(IS_NUMBER.represent(totals))) # Grand total --------------------------------------------------------- if cols is not None: grand_totals = get_total(report.totals, layers) add_total(TD(grand_totals)) tfoot = TFOOT(col_total) # Wrap up ------------------------------------------------------------- append = components.append append(thead) append(tbody) if show_totals: append(tfoot) # Chart data ---------------------------------------------------------- layer_label = s3_unicode(layer_label) BY = T("by") row_label = "%s %s" % (BY, s3_unicode(row_label)) if col_label: col_label = "%s %s" % (BY, s3_unicode(col_label)) if filter_query and hasattr(filter_query, "serialize_url"): filter_vars = filter_query.serialize_url(resource=report.resource) else: filter_vars = {} json_data = json.dumps( dict(t=layer_label, x=col_label, y=row_label, r=report.rows, c=report.cols, d=report.compact(n=50, represent=True), u=url, f=filter_vars, cell_lookup_table=cell_lookup_table)) self.report_data = Storage(row_label=row_label, col_label=col_label, layer_label=layer_label, json_data=json_data)