def __init__(self, user, *args, **kwargs): self.report_id = None if 'report_id' in kwargs: self.report_id = kwargs.pop('report_id') if 'chart_id' in kwargs: self.chart_id = kwargs.pop('chart_id') chart = get_object_or_404(Chart, pk=self.chart_id) self.report_id = chart.report_id super(ChartForm, self).__init__(*args, **kwargs) if not self.report_id: return report = get_object_or_404(Report, pk = self.report_id) chart = None if hasattr(self,'chart_id'): chart = get_object_or_404(Chart, pk=self.chart_id) model = loads(report.model) object = model.name object = object.split('.') module_name = object[0] + '.' + object[1] + '.' + object[2] import_name = object[3] module = __import__(module_name, globals(), locals(), [import_name], -1) classobj = getattr(module, import_name) unfiltered_set = classobj.objects.exclude(trash=True) set = [] for s in unfiltered_set: filtered = False for field in model.fields: if field.filters and str(getattr(s, field.name)) not in field.filters: filtered = True if not filtered: set.append(s) #perhaps do type checking on a setting list of types (for each type) self.fields['grouping'].choices = [('', '--------')] # Check for group groupname = None groups = None for field in model.fields: self.fields['grouping'].choices.append((str(field.name), str(field.name).replace('_',' ').title())) if field.groupby == 1: self.fields['grouping'].initial = str(field.name) if chart: options = loads(chart.options) for f in options: if f in self.fields: self.fields[f].initial = options[f]
def report_group(request, report_id, field_name, response_format='html'): "View to Group by a given field in a report" t = get_object_or_404(Report, pk=report_id) if not request.user.get_profile().has_permission(t, mode='w'): return user_denied(request, message="You don't have access to this Report") model = loads(t.model) #Check if this field is already grouped, if so then remove grouping thisfield = model.get_field(field_name) if thisfield.groupby == 1: thisfield.groupby = 0 else: #Other wise reset grouping and set selected field as groupfield for field in model.fields: field.groupby = 0 field = model.get_field(field_name) field.groupby = 1 t.model = dumps(model) t.save() return report_edit(request, report_id=report_id, response_format=response_format)
def is_field_number(report, field_name): model = loads(report.model) classobj = model.get_class_object() field = classobj._meta.get_field_by_name(field_name)[0] if number_field_regex.match(field.get_internal_type()): return True return False
def report_filter_remove(request, report_id, field_name, filter_index, response_format='html'): "Remove a Filter on a given field for a Report" report = get_object_or_404(Report, pk=report_id) if not request.user.get_profile().has_permission(report, mode='w'): return user_denied(request, message="You don't have write access to this Report") model = loads(report.model) field = model.get_field(field_name) field.filters.pop(int(filter_index)-1) report.model = dumps(model) report.save() return HttpResponseRedirect(reverse('reports_report_edit', args=[int(report_id)]))
def save(self): #add filter to field if not self.data['choice']: return t = self.report model = loads(t.model) classobj = model.get_class_object() xfield = classobj._meta.get_field_by_name(self.field_name)[0] field = model.get_field(self.field_name) if not field.filters: field.filters = [] c = self.data['choice'] type = xfield.get_internal_type() if type == 'ManyToManyField': c = xfield.related.parent_model.objects.filter(pk=c)[0] if type == 'ForeignKey': c = xfield.related.parent_model.objects.filter(pk=c)[0] display_choice = c if hasattr(self.fields['choice'],'choices'): for choice, dc in self.fields['choice'].choices: if unicode(c)==unicode(choice): display_choice = dc break for choice, dc in self.fields['operand'].choices: if unicode(self.data['operand'])==unicode(choice): display_operand = dc break display = "%s %s %s" % (field.get_human_name(), display_operand, unicode(display_choice)) field.filters.append({'choice': c, 'operand': self.data['operand'], 'display': display }) t.model = dumps(model) t.save()
def report_edit(request, report_id=None, response_format='html'): "Create new report based on user choice" report = get_object_or_404(Report, pk=report_id) if not request.user.get_profile().has_permission(report, mode='w'): return user_denied(request, message="You don't have access to edit this Report") model = loads(report.model) if request.POST and 'commit' in request.POST: # UPDATE MODEL if 'report_name' in request.POST: report.name = request.POST['report_name'] fieldnames = [] aggregations = {} for key in request.POST: if 'field' in key: fieldnames.append(request.POST[key]) elif 'aggregation-' in key: aggregations[key[12:]] = request.POST[key] for field in model.fields: field.aggregation = aggregations.get(field.name, None) if field.name in fieldnames: field.display = True else: field.display = False report.model = dumps(model) report.save() if 'commit' in request.POST: return HttpResponseRedirect(reverse('reports_report_view', args=[report.id])) return render_to_response('reports/report_edit', {'report': report, 'model':model, }, context_instance=RequestContext(request), response_format=response_format)
def __init__(self, user, *args, **kwargs): if not (kwargs.has_key('report') and kwargs.has_key('field_name')): return report = kwargs.pop('report') field_name = kwargs.pop('field_name') super(FilterForm, self).__init__(*args, **kwargs) model = loads(report.model) self.report = report self.field_name = field_name classobj = model.get_class_object() field = classobj._meta.get_field_by_name(field_name)[0] #TODO: Provisions for ManyToMany fields self.fields['operand'] = forms.ChoiceField() if field.get_internal_type() == 'ForeignKey': self.fields['choice'] = forms.ModelChoiceField(queryset = Object.filter_permitted(user, field.related.parent_model.objects.all(), mode='x')) fc = (('is','is'),('not','is not')) elif field.get_internal_type() == 'DateTimeField': self.fields['choice'] = forms.DateTimeField() self.fields['choice'].widget.attrs.update({'class': 'datetimepicker'}) fc = (('beforedatetime','before'),('afterdatetime','after')) elif field.get_internal_type() == 'DateField': self.fields['choice'] = forms.DateField() self.fields['choice'].widget.attrs.update({'class': 'datepicker'}) fc = (('beforedate','before'),('afterdate','after'),('on','on')) else: self.fields['choice'] = field.formfield() fc = (('is','is'),('not','is not')) self.fields['operand'].choices = fc self.fields['operand'].label = "" self.fields['choice'].label = "" self.fields['choice'].help_text = ""
def _get_report_content(report, request=None): model = loads(report.model) object = model.name object = object.split('.') module_name = object[0] + '.' + object[1] + '.' + object[2] import_name = object[3] module = __import__(module_name, globals(), locals(), [import_name], -1) classobj = getattr(module, import_name) if request: unfiltered_set = Object.filter_by_request(request, classobj.objects) else: unfiltered_set = classobj.objects.exclude(trash=True) # construct filter filters = {} excludes = {} for field in model.fields: for filter in field.filters: if filter['operand']=='is': filters.setdefault(field.name+'__in', []).append( filter['choice'] ) elif filter['operand']=='not': excludes.setdefault(field.name+'__in', []).append( filter['choice'] ) elif filter['operand']=='beforedate': filters[field.name+'__gte'] = datetime.date(datetime.strptime(filter['choice'], '%m/%d/%Y')) elif filter['operand']=='afterdate': filters[field.name+'__lte'] = datetime.date(datetime.strptime(filter['choice'], '%m/%d/%Y')) elif filter['operand']=='beforedatetime': filters[field.name+'__gte'] = datetime.strptime(filter['choice'], '%m/%d/%Y %H:%M') elif filter['operand']=='afterdatetime': filters[field.name+'__lte'] = datetime.strptime(filter['choice'], '%m/%d/%Y %H:%M') elif filter['operand']=='on': filters.setdefault(field.name+'__in', []).append( datetime.strptime(filter['choice'], '%m/%d/%Y') ) set = unfiltered_set.filter(**filters).exclude(**excludes) # Check for group groupname = None groups = None for field in model.fields: if field.groupby == 1: groupname = field.name if groupname: xfield = classobj._meta.get_field_by_name(groupname)[0] xtype = xfield.get_internal_type() if xtype == 'ManyToManyField': set = sorted(set, key=lambda item: (", ".join([unicode(i) for i in getattr(item, groupname).all()])), reverse=True) groups, groupnames = [], [] for obj in set: for n in getattr(obj, groupname).all(): if n not in groupnames: groupnames.append(n) for n in groupnames: l = [] for obj in set: if n in getattr(obj, groupname).all(): l.append(obj) groups.append((unicode(n), l)) elif xtype == ('DateTimeField' or 'DateField'): set = set.order_by(groupname) #set = sorted(set, key = lambda item: getattr(item,groupname)) #TODO: Fix this sort groups, groupnames, l, ng = [], [], [], [] n = None if xtype == 'DateTimeField': def dt(ob): return getattr(ob, groupname).date() else: def dt(ob): return getattr(ob, groupname) for x in set: n = dt(x) if n: break if n: for obj in set: if getattr(obj, groupname): if dt(obj) == n: l.append(obj) else: groups.append((unicode(n), l)) l = [] n = dt(obj) l.append(obj) else: ng.append(obj) if ng: groups.append(('None', ng)) else: set = sorted(set, key=lambda item: unicode(item.get_field_value(groupname)), reverse=True) groups = [] for g, ks in groupby(set, key=lambda item: unicode(item.get_field_value(groupname))): groups.append( (g, list(ks)) ) xfield = set[0]._meta.get_field_by_name(groupname)[0] # Count aggregate functions agg_funcs = {} for field in model.fields: # get fields and aggregate functions for them if field.display and getattr(field, 'aggregation', None): xfield = classobj._meta.get_field_by_name(field.name)[0] if number_field_regex.match(xfield.get_internal_type()) \ and aggregate_functions.has_key(field.aggregation): agg_funcs[field.name] = aggregate_functions[field.aggregation]['function'] aggregations = {} if agg_funcs: for grouper, ls in groups if groups else (('set', set),): data = {} for s in ls: for key in agg_funcs: data.setdefault(key, []).append(getattr(s, key, 0)) aggrs = {} for key, func in agg_funcs.items(): aggrs[key] = func(data.get(key,[0,])) aggregations[grouper] = aggrs return {'model': model, 'set': set, 'groups':groups, 'groupname':groupname, 'aggregations':aggregations}
def display_chart(context, chart, skip_group=False): "Return HTML for chart" request = context["request"] response_format = "html" if "response_format" in context: response_format = context["response_format"] options = loads(chart.options) content = _get_report_content(chart.report, request) objs = content["set"] chart_dict = {} field_name = options["grouping"] model = loads(chart.report.model) chart_dict["yAxis"] = { "allowDecimals": False, "title": {"text": model.name.split(".")[-1] + " Count vs. " + field_name.replace("_", " ").title()}, } chart_dict["xAxis"] = {} try: xfield = objs[0]._meta.get_field_by_name(field_name)[0] except: chart.delete() return def get_date(g, mindate): if g and g != datetime.min.date(): return g else: return mindate if xfield.get_internal_type() == "ManyToManyField": l = [] for obj in objs: for mi in getattr(obj, field_name).all(): l.append(unicode(mi)) elif xfield.get_internal_type() == "DateTimeField" or xfield.get_internal_type() == "DateField": chart_dict["xAxis"]["labels"] = {"align": "left", "x": 3, "y": 15} #'rotation':90, l, m, datelist = [], [], [] maxdate = None mindate = None for obj in objs: if getattr(obj, field_name): x = getattr(obj, field_name) if xfield.get_internal_type() == "DateTimeField": x = x.date() if not maxdate or x > maxdate: maxdate = x if not mindate or x < mindate: mindate = x datelist.append(x) if unicode(x) not in m: m.append(unicode(x)) else: datelist.append(datetime.min.date()) while datetime.min.date() in datelist: datelist.append(mindate) datelist.remove(datetime.min.date()) datelist = sorted(datelist, key=lambda g: get_date(g, mindate)) l = [unicode(g) for g in datelist] # chart_dict['xAxis']['categories']=m chart_dict["xAxis"]["type"] = "datetime" td = maxdate - mindate # print (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6 chart_dict["zoomType"] = "x" chart_dict["xAxis"]["tickInterval"] = (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6) / 10 ** 4 # chart_dict['xAxis']['tickWidth']= 0, chart_dict["maxZoom"] = 14 * 24 * 3600000 # 2wks # chart_dict['xAxis']['gridLineWidth']= 1, chart_dict["series"] = [{"name": model.name.split(".")[-1], "data": []}] for x in set(l): chart_dict["series"][0]["data"].append(("%s UTC" % x, l.count(x))) else: l = [unicode(obj.get_field_value(field_name)) for obj in objs] if not "series" in chart_dict: chart_dict["series"] = [] # chart_dict['series'].append({'name':field_name, 'data': [{'name': x, 'y':l.count(x)} for x in set(l)]}) chart_dict["series"].append( {"name": field_name.replace("_", " ").title(), "data": [[x, l.count(x)] for x in set(l)]} ) # for x in set(l): # chart_dict['series'].append({'name':x, 'data': l.count(x)}) # chart_dict['series'].append({'data':[{'name':x, 'y': [l.count(x)]} for x in set(l)]}) if not "xAxis" in chart_dict: chart_dict["xAxis"]["categories"] = [x for x in set(l)] # Chart type specific options if "legend" in options and options["legend"] == "on": chart_dict["legend"] = { "layout": "vertical", "align": "right", "verticalAlign": "top", "x": -10, "y": 100, "borderWidth": 0, } if "title" in options: chart_dict["title"] = {"text": options["title"]} # Create a hash and use it as a unqiue div id and var name for the chart. hasher = hashlib.md5() hasher.update(str(random())) id = "chartcontainer" + str(hasher.hexdigest()) # Disable animation for when saving as PDF chart_dict["chart"] = {"renderTo": id, "defaultSeriesType": options["type"]} # chart_dict['plotOptions'] = {'series': {'animation': False}} chart_dict["plotOptions"] = { "pie": {"allowPointSelect": True, "cursor": "pointer", "dataLabels": {"enabled": False}, "showInLegend": True} } chart_dict["credits"] = {"enabled": False} rendered_options = json.dumps(chart_dict) rendered_options = ( rendered_options[:-1] + ", tooltip: {formatter: function() {return '<b>'+ this.point.name +'</b>: '+ this.y;}}}" ) if "type" in chart_dict["xAxis"] and chart_dict["xAxis"]["type"] == "datetime": rendered_options += """ datedata = []; jQuery.each(options.series[0].data, function(i,item){ date = Date.parse(item[0]); count = item[1]; datedata.push([date, count]); }); options.series[0].data = datedata; function merge_options(obj1,obj2){ var obj3 = {}; for (attrname in obj1) { obj3[attrname] = obj1[attrname]; } for (attrname in obj2) { obj3[attrname] = obj2[attrname]; } return obj3; } var dateoptions = { tooltip: { shared: true, crosshairs: true }, }; options = merge_options(options, dateoptions); """ return Markup( render_to_string( "reports/tags/chart", { "rendered_options": rendered_options, "id": id, "chart_id": chart.id, "chart": chart, "name": options["title"], }, context_instance=RequestContext(request), response_format=response_format, ) )