From 58600cf8e76f270969ded6ec63ac0908f39dae09 Mon Sep 17 00:00:00 2001 From: Alexandru DAMIAN Date: Mon, 8 Jun 2015 11:01:43 +0100 Subject: bitbake: toaster: toaster table add raw data We add in a JSON response both the raw data and the rendered version for display. The rendered fields start with "static:" to mark a different "namespace". The toaster.js is updated to always display the "static:" version of a field, if it exists (and ignore the raw data unless the static rendering is missing). (Bitbake rev: 928ee3fd4b52ea14b7eb704f1f27351362a9d27a) Signed-off-by: Alexandru DAMIAN Signed-off-by: Richard Purdie --- bitbake/lib/toaster/toastergui/static/js/table.js | 14 +++++++++- bitbake/lib/toaster/toastergui/views.py | 31 ++++++++++++++++++++++- bitbake/lib/toaster/toastergui/widgets.py | 16 ++++++++---- 3 files changed, 54 insertions(+), 7 deletions(-) (limited to 'bitbake/lib/toaster') diff --git a/bitbake/lib/toaster/toastergui/static/js/table.js b/bitbake/lib/toaster/toastergui/static/js/table.js index 7588a4ab9a..80e9ec2392 100644 --- a/bitbake/lib/toaster/toastergui/static/js/table.js +++ b/bitbake/lib/toaster/toastergui/static/js/table.js @@ -113,8 +113,20 @@ function tableInit(ctx){ for (var i in tableData.rows){ var row = $(""); for (var key_j in tableData.rows[i]){ + /* if we have a static: version of a key, prefer the static: version for rendering */ + var orig_key_j = key_j; + + if (key_j.indexOf("static:") === 0) { + if (key_j.substr("static:".length) in tableData.rows[i]) { + continue; + } + orig_key_j = key_j.substr("static:".length) + } else if (("static:" + key_j) in tableData.rows[i]) { + key_j = "static:" + key_j; + } + var td = $(""); - td.prop("class", key_j); + td.prop("class", orig_key_j); if (tableData.rows[i][key_j]){ td.html(tableData.rows[i][key_j]); } diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index 91c4fa2543..280159ad2c 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py @@ -87,6 +87,35 @@ def _project_recent_build_list(prj): list(prj.buildrequest_set.filter(state__in=[BuildRequest.REQ_COMPLETED, BuildRequest.REQ_FAILED]).order_by("-pk")[:3])) + +def objtojson(obj): + from django.db.models.query import QuerySet + from django.db.models import Model, IntegerField + from django.db.models.fields.related import ForeignKey + + if isinstance(obj, datetime): + return obj.isoformat() + elif isinstance(obj, timedelta): + return obj.total_seconds() + elif isinstance(obj, QuerySet) or isinstance(obj, set): + return list(obj) + elif type(obj).__name__ == "RelatedManager": + return [x.pk for x in obj.all()] + elif hasattr( obj, '__dict__') and isinstance(obj, Model): + d = obj.__dict__ + nd = dict(d) + for di in d.keys(): + if di.startswith("_"): + del nd[di] + elif isinstance(d[di], Model): + nd[di] = d[di].pk + elif isinstance(d[di], int) and hasattr(obj, "get_%s_display" % di): + nd[di] = getattr(obj, "get_%s_display" % di)() + return nd + else: + raise TypeError("Unserializable object %s (%s) of type %s" % ( obj, dir(obj), type(obj))) + + def _template_renderer(template): def func_wrapper(view): def returned_wrapper(request, *args, **kwargs): @@ -127,7 +156,7 @@ def _template_renderer(template): else: raise TypeError("Unserializable object %s of type %s" % ( obj, type(obj))) - return HttpResponse(jsonfilter(context, default=_objtojson ), + return HttpResponse(jsonfilter(context, default=objtojson ), content_type = "application/json; charset=utf-8") else: return render(request, template, context) diff --git a/bitbake/lib/toaster/toastergui/widgets.py b/bitbake/lib/toaster/toastergui/widgets.py index 4347a3f081..82b7514bd8 100644 --- a/bitbake/lib/toaster/toastergui/widgets.py +++ b/bitbake/lib/toaster/toastergui/widgets.py @@ -37,6 +37,7 @@ import json import collections import operator +from toastergui.views import objtojson class ToasterTable(TemplateView): def __init__(self, *args, **kwargs): @@ -275,19 +276,25 @@ class ToasterTable(TemplateView): for col in self.columns: field = col['field_name'] + if not field: + field = col['static_data_name'] + if not field: + raise Exception("Must supply a field_name or static_data_name for column %s.%s" % (self.__class__.__name__,col)) # Check if we need to process some static data if "static_data_name" in col and col['static_data_name']: - required_data[col['static_data_name']] = self.render_static_data(col['static_data_template'], row) + required_data["static:%s" % col['static_data_name']] = self.render_static_data(col['static_data_template'], row) # Overwrite the field_name with static_data_name # so that this can be used as the html class name col['field_name'] = col['static_data_name'] - else: + + if True: # we add the raw model data at all times model_data = row # Traverse to any foriegn key in the object hierachy for subfield in field.split("__"): - model_data = getattr(model_data, subfield) + if hasattr(model_data, subfield): + model_data = getattr(model_data, subfield) # The field could be a function on the model so check # If it is then call it if isinstance(model_data, types.MethodType): @@ -299,8 +306,7 @@ class ToasterTable(TemplateView): except FieldError: print "Error: Requested field does not exist" - - data = json.dumps(data, indent=2, cls=DjangoJSONEncoder) + data = json.dumps(data, indent=2, default=objtojson) cache.set(cache_name, data, 60*30) return data -- cgit v1.2.3-54-g00ecf