diff options
author | Michael Wood <michael.g.wood@intel.com> | 2016-05-16 14:50:40 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-05-17 14:43:30 +0100 |
commit | 54bf7cce48547289489203812f2e01cb755f0db4 (patch) | |
tree | b744123fed2c7e15ab4d1a45c1dce988d3dd4a58 | |
parent | a906a09c730683ee14b84fd890d109f52c9e3b02 (diff) | |
download | poky-54bf7cce48547289489203812f2e01cb755f0db4.tar.gz |
bitbake: toaster: toastertables: Clean up and fix up a number of items
- Remove the unused 'computation' field
- Remove the code to try to make the tables behave like an api
- Remove custom JSON encoder in favour of DjangoJSONEncoder
- Simplify get_data and add comments
- Add exception type instead of using generic Exception
- Clean up python style warnings
(Bitbake rev: 16d8198e8f6668c5fa5467ff4bda86c5d66a6cad)
Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r-- | bitbake/lib/toaster/toastergui/static/js/table.js | 21 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/tables.py | 11 | ||||
-rw-r--r-- | bitbake/lib/toaster/toastergui/widgets.py | 127 |
3 files changed, 72 insertions, 87 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/js/table.js b/bitbake/lib/toaster/toastergui/static/js/table.js index f738144ae5..7f76f555fc 100644 --- a/bitbake/lib/toaster/toastergui/static/js/table.js +++ b/bitbake/lib/toaster/toastergui/static/js/table.js | |||
@@ -101,27 +101,8 @@ function tableInit(ctx){ | |||
101 | var row = $("<tr></tr>"); | 101 | var row = $("<tr></tr>"); |
102 | column_index = -1; | 102 | column_index = -1; |
103 | for (var key_j in tableData.rows[i]){ | 103 | for (var key_j in tableData.rows[i]){ |
104 | |||
105 | /* if we have a static: version of a key, prefer the static: version for rendering */ | ||
106 | var orig_key_j = key_j; | ||
107 | |||
108 | if (key_j.indexOf("static:") === 0) { | ||
109 | if (key_j.substr("static:".length) in tableData.rows[i]) { | ||
110 | continue; | ||
111 | } | ||
112 | orig_key_j = key_j.substr("static:".length) | ||
113 | } else if (("static:" + key_j) in tableData.rows[i]) { | ||
114 | key_j = "static:" + key_j; | ||
115 | } | ||
116 | |||
117 | /* we skip over un-displayable column entries */ | ||
118 | column_index += 1; | ||
119 | if (! tableData.columns[column_index].displayable) { | ||
120 | continue; | ||
121 | } | ||
122 | |||
123 | var td = $("<td></td>"); | 104 | var td = $("<td></td>"); |
124 | td.prop("class", orig_key_j); | 105 | td.prop("class", key_j); |
125 | if (tableData.rows[i][key_j]){ | 106 | if (tableData.rows[i][key_j]){ |
126 | td.html(tableData.rows[i][key_j]); | 107 | td.html(tableData.rows[i][key_j]); |
127 | } | 108 | } |
diff --git a/bitbake/lib/toaster/toastergui/tables.py b/bitbake/lib/toaster/toastergui/tables.py index d375da434f..d21bed1fbe 100644 --- a/bitbake/lib/toaster/toastergui/tables.py +++ b/bitbake/lib/toaster/toastergui/tables.py | |||
@@ -190,17 +190,6 @@ class LayersTable(ToasterTable): | |||
190 | static_data_name="add-del-layers", | 190 | static_data_name="add-del-layers", |
191 | static_data_template='{% include "layer_btn.html" %}') | 191 | static_data_template='{% include "layer_btn.html" %}') |
192 | 192 | ||
193 | project = Project.objects.get(pk=kwargs['pid']) | ||
194 | self.add_column(title="LayerDetailsUrl", | ||
195 | displayable = False, | ||
196 | field_name="layerdetailurl", | ||
197 | computation = lambda x: reverse('layerdetails', args=(project.id, x.id))) | ||
198 | |||
199 | self.add_column(title="name", | ||
200 | displayable = False, | ||
201 | field_name="name", | ||
202 | computation = lambda x: x.layer.name) | ||
203 | |||
204 | 193 | ||
205 | class MachinesTable(ToasterTable): | 194 | class MachinesTable(ToasterTable): |
206 | """Table of Machines in Toaster""" | 195 | """Table of Machines in Toaster""" |
diff --git a/bitbake/lib/toaster/toastergui/widgets.py b/bitbake/lib/toaster/toastergui/widgets.py index d2ef5d3dba..4117031830 100644 --- a/bitbake/lib/toaster/toastergui/widgets.py +++ b/bitbake/lib/toaster/toastergui/widgets.py | |||
@@ -43,9 +43,12 @@ import urllib | |||
43 | import logging | 43 | import logging |
44 | logger = logging.getLogger("toaster") | 44 | logger = logging.getLogger("toaster") |
45 | 45 | ||
46 | from toastergui.views import objtojson | ||
47 | from toastergui.tablefilter import TableFilterMap | 46 | from toastergui.tablefilter import TableFilterMap |
48 | 47 | ||
48 | |||
49 | class NoFieldOrDataNme(Exception): | ||
50 | pass | ||
51 | |||
49 | class ToasterTable(TemplateView): | 52 | class ToasterTable(TemplateView): |
50 | def __init__(self, *args, **kwargs): | 53 | def __init__(self, *args, **kwargs): |
51 | super(ToasterTable, self).__init__() | 54 | super(ToasterTable, self).__init__() |
@@ -63,25 +66,19 @@ class ToasterTable(TemplateView): | |||
63 | self.empty_state = "Sorry - no data found" | 66 | self.empty_state = "Sorry - no data found" |
64 | self.default_orderby = "" | 67 | self.default_orderby = "" |
65 | 68 | ||
66 | # add the "id" column, undisplayable, by default | ||
67 | self.add_column(title="Id", | ||
68 | displayable=False, | ||
69 | orderable=True, | ||
70 | field_name="id") | ||
71 | |||
72 | # prevent HTTP caching of table data | 69 | # prevent HTTP caching of table data |
73 | @cache_control(must_revalidate=True, max_age=0, no_store=True, no_cache=True) | 70 | @cache_control(must_revalidate=True, |
71 | max_age=0, no_store=True, no_cache=True) | ||
74 | def dispatch(self, *args, **kwargs): | 72 | def dispatch(self, *args, **kwargs): |
75 | return super(ToasterTable, self).dispatch(*args, **kwargs) | 73 | return super(ToasterTable, self).dispatch(*args, **kwargs) |
76 | 74 | ||
77 | def get_context_data(self, **kwargs): | 75 | def get_context_data(self, **kwargs): |
78 | context = super(ToasterTable, self).get_context_data(**kwargs) | 76 | context = super(ToasterTable, self).get_context_data(**kwargs) |
79 | context['title'] = self.title | 77 | context['title'] = self.title |
80 | context['table_name'] = type(self).__name__.lower() | 78 | context['table_name'] = type(self).__name__.lower() |
81 | 79 | ||
82 | return context | 80 | return context |
83 | 81 | ||
84 | |||
85 | def get(self, request, *args, **kwargs): | 82 | def get(self, request, *args, **kwargs): |
86 | if request.GET.get('format', None) == 'json': | 83 | if request.GET.get('format', None) == 'json': |
87 | 84 | ||
@@ -102,8 +99,6 @@ class ToasterTable(TemplateView): | |||
102 | return super(ToasterTable, self).get(request, *args, **kwargs) | 99 | return super(ToasterTable, self).get(request, *args, **kwargs) |
103 | 100 | ||
104 | def get_filter_info(self, request, **kwargs): | 101 | def get_filter_info(self, request, **kwargs): |
105 | data = None | ||
106 | |||
107 | self.setup_filters(**kwargs) | 102 | self.setup_filters(**kwargs) |
108 | 103 | ||
109 | search = request.GET.get("search", None) | 104 | search = request.GET.get("search", None) |
@@ -117,13 +112,18 @@ class ToasterTable(TemplateView): | |||
117 | cls=DjangoJSONEncoder) | 112 | cls=DjangoJSONEncoder) |
118 | 113 | ||
119 | def setup_columns(self, *args, **kwargs): | 114 | def setup_columns(self, *args, **kwargs): |
120 | """ function to implement in the subclass which sets up the columns """ | 115 | """ function to implement in the subclass which sets up |
116 | the columns """ | ||
121 | pass | 117 | pass |
118 | |||
122 | def setup_filters(self, *args, **kwargs): | 119 | def setup_filters(self, *args, **kwargs): |
123 | """ function to implement in the subclass which sets up the filters """ | 120 | """ function to implement in the subclass which sets up the |
121 | filters """ | ||
124 | pass | 122 | pass |
123 | |||
125 | def setup_queryset(self, *args, **kwargs): | 124 | def setup_queryset(self, *args, **kwargs): |
126 | """ function to implement in the subclass which sets up the queryset""" | 125 | """ function to implement in the subclass which sets up the |
126 | queryset""" | ||
127 | pass | 127 | pass |
128 | 128 | ||
129 | def add_filter(self, table_filter): | 129 | def add_filter(self, table_filter): |
@@ -137,7 +137,6 @@ class ToasterTable(TemplateView): | |||
137 | def add_column(self, title="", help_text="", | 137 | def add_column(self, title="", help_text="", |
138 | orderable=False, hideable=True, hidden=False, | 138 | orderable=False, hideable=True, hidden=False, |
139 | field_name="", filter_name=None, static_data_name=None, | 139 | field_name="", filter_name=None, static_data_name=None, |
140 | displayable=True, computation=None, | ||
141 | static_data_template=None): | 140 | static_data_template=None): |
142 | """Add a column to the table. | 141 | """Add a column to the table. |
143 | 142 | ||
@@ -155,18 +154,15 @@ class ToasterTable(TemplateView): | |||
155 | as data | 154 | as data |
156 | """ | 155 | """ |
157 | 156 | ||
158 | self.columns.append({'title' : title, | 157 | self.columns.append({'title': title, |
159 | 'help_text' : help_text, | 158 | 'help_text': help_text, |
160 | 'orderable' : orderable, | 159 | 'orderable': orderable, |
161 | 'hideable' : hideable, | 160 | 'hideable': hideable, |
162 | 'hidden' : hidden, | 161 | 'hidden': hidden, |
163 | 'field_name' : field_name, | 162 | 'field_name': field_name, |
164 | 'filter_name' : filter_name, | 163 | 'filter_name': filter_name, |
165 | 'static_data_name': static_data_name, | 164 | 'static_data_name': static_data_name, |
166 | 'static_data_template': static_data_template, | 165 | 'static_data_template': static_data_template}) |
167 | 'displayable': displayable, | ||
168 | 'computation': computation, | ||
169 | }) | ||
170 | 166 | ||
171 | def set_column_hidden(self, title, hidden): | 167 | def set_column_hidden(self, title, hidden): |
172 | """ | 168 | """ |
@@ -190,8 +186,8 @@ class ToasterTable(TemplateView): | |||
190 | """Utility function to render the static data template""" | 186 | """Utility function to render the static data template""" |
191 | 187 | ||
192 | context = { | 188 | context = { |
193 | 'extra' : self.static_context_extra, | 189 | 'extra': self.static_context_extra, |
194 | 'data' : row, | 190 | 'data': row, |
195 | } | 191 | } |
196 | 192 | ||
197 | context = Context(context) | 193 | context = Context(context) |
@@ -241,7 +237,7 @@ class ToasterTable(TemplateView): | |||
241 | 237 | ||
242 | if not hasattr(self.queryset.model, 'search_allowed_fields'): | 238 | if not hasattr(self.queryset.model, 'search_allowed_fields'): |
243 | raise Exception("Search fields aren't defined in the model %s" | 239 | raise Exception("Search fields aren't defined in the model %s" |
244 | % self.queryset.model) | 240 | % self.queryset.model) |
245 | 241 | ||
246 | search_queries = [] | 242 | search_queries = [] |
247 | for st in search_term.split(" "): | 243 | for st in search_term.split(" "): |
@@ -254,7 +250,6 @@ class ToasterTable(TemplateView): | |||
254 | 250 | ||
255 | self.queryset = self.queryset.filter(search_queries) | 251 | self.queryset = self.queryset.filter(search_queries) |
256 | 252 | ||
257 | |||
258 | def get_data(self, request, **kwargs): | 253 | def get_data(self, request, **kwargs): |
259 | """ | 254 | """ |
260 | Returns the data for the page requested with the specified | 255 | Returns the data for the page requested with the specified |
@@ -262,7 +257,8 @@ class ToasterTable(TemplateView): | |||
262 | 257 | ||
263 | filters: filter and action name, e.g. "outcome:build_succeeded" | 258 | filters: filter and action name, e.g. "outcome:build_succeeded" |
264 | filter_value: value to pass to the named filter+action, e.g. "on" | 259 | filter_value: value to pass to the named filter+action, e.g. "on" |
265 | (for a toggle filter) or "2015-12-11,2015-12-12" (for a date range filter) | 260 | (for a toggle filter) or "2015-12-11,2015-12-12" |
261 | (for a date range filter) | ||
266 | """ | 262 | """ |
267 | 263 | ||
268 | page_num = request.GET.get("page", 1) | 264 | page_num = request.GET.get("page", 1) |
@@ -313,16 +309,16 @@ class ToasterTable(TemplateView): | |||
313 | page = paginator.page(1) | 309 | page = paginator.page(1) |
314 | 310 | ||
315 | data = { | 311 | data = { |
316 | 'total' : self.queryset.count(), | 312 | 'total': self.queryset.count(), |
317 | 'default_orderby' : self.default_orderby, | 313 | 'default_orderby': self.default_orderby, |
318 | 'columns' : self.columns, | 314 | 'columns': self.columns, |
319 | 'rows' : [], | 315 | 'rows': [], |
320 | 'error' : "ok", | 316 | 'error': "ok", |
321 | } | 317 | } |
322 | 318 | ||
323 | try: | 319 | try: |
324 | for row in page.object_list: | 320 | for model_obj in page.object_list: |
325 | #Use collection to maintain the order | 321 | # Use collection to maintain the order |
326 | required_data = collections.OrderedDict() | 322 | required_data = collections.OrderedDict() |
327 | 323 | ||
328 | for col in self.columns: | 324 | for col in self.columns: |
@@ -330,38 +326,57 @@ class ToasterTable(TemplateView): | |||
330 | if not field: | 326 | if not field: |
331 | field = col['static_data_name'] | 327 | field = col['static_data_name'] |
332 | if not field: | 328 | if not field: |
333 | raise Exception("Must supply a field_name or static_data_name for column %s.%s" % (self.__class__.__name__,col)) | 329 | raise NoFieldOrDataNme("Must supply a field_name or" |
330 | "static_data_name for column" | ||
331 | "%s.%s" % | ||
332 | (self.__class__.__name__, col)) | ||
333 | |||
334 | # Check if we need to process some static data | 334 | # Check if we need to process some static data |
335 | if "static_data_name" in col and col['static_data_name']: | 335 | if "static_data_name" in col and col['static_data_name']: |
336 | required_data["static:%s" % col['static_data_name']] = self.render_static_data(col['static_data_template'], row) | ||
337 | |||
338 | # Overwrite the field_name with static_data_name | 336 | # Overwrite the field_name with static_data_name |
339 | # so that this can be used as the html class name | 337 | # so that this can be used as the html class name |
340 | |||
341 | col['field_name'] = col['static_data_name'] | 338 | col['field_name'] = col['static_data_name'] |
342 | 339 | ||
343 | # compute the computation on the raw data if needed | 340 | # Render the template given |
344 | model_data = row | 341 | required_data[col['static_data_name']] = \ |
345 | if col['computation']: | 342 | self.render_static_data( |
346 | model_data = col['computation'](row) | 343 | col['static_data_template'], model_obj) |
347 | else: | 344 | else: |
348 | # Traverse to any foriegn key in the object hierachy | 345 | # Traverse to any foriegn key in the field |
349 | for subfield in field.split("__"): | 346 | # e.g. recipe__layer_version__name |
350 | if hasattr(model_data, subfield): | 347 | model_data = None |
351 | model_data = getattr(model_data, subfield) | 348 | |
352 | # The field could be a function on the model so check | 349 | if "__" in field: |
353 | # If it is then call it | 350 | for subfield in field.split("__"): |
351 | if not model_data: | ||
352 | # The first iteration is always going to | ||
353 | # be on the actual model object instance. | ||
354 | # Subsequent ones are on the result of | ||
355 | # that. e.g. forieng key objects | ||
356 | model_data = getattr(model_obj, | ||
357 | subfield) | ||
358 | else: | ||
359 | model_data = getattr(model_data, | ||
360 | subfield) | ||
361 | |||
362 | else: | ||
363 | model_data = getattr(model_obj, | ||
364 | col['field_name']) | ||
365 | |||
366 | # We might have a model function as the field so | ||
367 | # call it to return the data needed | ||
354 | if isinstance(model_data, types.MethodType): | 368 | if isinstance(model_data, types.MethodType): |
355 | model_data = model_data() | 369 | model_data = model_data() |
356 | 370 | ||
357 | required_data[col['field_name']] = model_data | 371 | required_data[col['field_name']] = model_data |
358 | 372 | ||
359 | data['rows'].append(required_data) | 373 | data['rows'].append(required_data) |
360 | 374 | ||
361 | except FieldError: | 375 | except FieldError: |
362 | # pass it to the user - programming-error here | 376 | # pass it to the user - programming-error here |
363 | raise | 377 | raise |
364 | data = json.dumps(data, indent=2, default=objtojson) | 378 | |
379 | data = json.dumps(data, indent=2, cls=DjangoJSONEncoder) | ||
365 | cache.set(cache_name, data, 60*30) | 380 | cache.set(cache_name, data, 60*30) |
366 | 381 | ||
367 | return data | 382 | return data |