The problem
A view page such as
{{extend 'layout.html'}}
<br />
{{=BEAUTIFY(response._vars)}}
will produce a nice recursively traversed presentation showing keys and values of the dictionary output of the relevant controller function in a table. If a key value points to an inner dictionary, list or tuple then the value is recursed and shown as a table within a table and so on. Very convenient.
There are two problems
- The order of presentation of keys at a particular dictionary recursion level is alphabetical.
- Using the dict method is common in web2py to construct a dictionary. However with this method keys cannot have spaces in them and so the key will not appear as words when displayed in a view
The solution
As of 17 February 2010 there is a new version of BEAUTIFY in the web2py trunk that accepts a key filter attribute. A sample of how to use the filter is shown that does not require the BEAUTIFY class to be altered.
The last four lines of the six lines below are an addition to prior versions of BEAUTIFY in file gluon\html.py and provides a solution without altering the normal behaviour of BEAUTIFY.
if type(value) == types.LambdaType:
continue
if isinstance(key, str): # a key must be a string type
if key[1]=='_': # 'a_bcde_fghi' means 'bcde_fghi' is the key to be shown
key=key[2:] # remove 'a_' from 'a_bcde_fghi'
key=' '.join([x.capitalize() for x in key.split('_')]) # Converts remaining 'bcde_fghi' to 'Bcde Fghi'
The last three lines above can be replaced by the single line statement
key=' '.join([x.capitalize() for x in key[2:].split('_')]) if key[1:2]=='_' else key
This is important as this statement can be passed with a lambda into the new version of BEAUTIFY without modification to BEAUTIFY. The functionality of the last fourth line is not necessary when a view will only be used with a controller function that returns dictionaries prepared with the dict method; as keys of dict methods can only be strings. Alternatively a safer single statement version that replaces all the last four lines is
key=' '.join([x.capitalize() for x in key[2:].split('_')]) if isinstance(key, str) and key[1:2]=='_' else key
The code examines the second character of the key. If this character is '_' it removes the first two characters. This means the single characters A-Z, a-z and 0-9 are available to arbitrarily and conveniently reorder presentation independent of alphabetic order, as the first letter and the underscore following will be removed.
Also if the second character is '_', then the last line the of code replaces remaining underscores with a space and capitalizes the result.
If the second character is not an underscore then no replacement occurs and BEAUTIFY behaves as normal.
View example using BEAUTIFY keyfilter
Either use the view above and modify BEAUTIFY or use a newer BEAUTIFY with a view such as the following
{{extend 'layout.html'}}
<br />
{{=BEAUTIFY(response._vars, keyfilter=lambda key: ' '.join([x.capitalize() for x in key[2:].split('_')]) if key[1:2]=='_' else key)}}
Controller Function Examples
return dict(cde_fgh='world', ijk_lmn='hello') # Normal behaviour
cde_fgh: world
ijk_lmn: hello
return dict(b_cde_fgh='world', a_ijk_lmn='hello') # Altered behaviour: same keys but order reversed
Ijk Lmn: hello
Cde Fgh: world
Web Example
You can see an example of this technique in action at http://www.zgus.com/zgus/products/category_item/1
The view page uses BEAUTIFY with a keyfilter
The last statement of the category_item controller function is
return stripped_dict(dict(
a_product_category=item.title,
b_custom=item.custom,
d_products= _product_list,
e_category_documentation=_document_list,
f_video=_video_list,
g_about=item.about,
))
As for the quality of the linked videos in the page, I received a polite complaint from a senior executive of a well known corporation about their poor quality! Their main purpose is to demonstrate I work on further developing real product which is not yet ready to be marketed!
John Heenan
Comments (0)