Last active
October 12, 2016 09:08
-
-
Save dz0/ef4bea4e6f4aaf21f084c06190efecf6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| def table_template(table): | |
| from gluon.html import TR, TD, TABLE, TAG | |
| def FONT(*args, **kwargs): | |
| return TAG.font(*args, **kwargs) | |
| def types(field): | |
| f_type = field.type | |
| if not isinstance(f_type,str): | |
| return ' ' | |
| elif f_type == 'string': | |
| return field.length | |
| elif f_type == 'id': | |
| return B('pk') | |
| elif f_type.startswith('reference') or \ | |
| f_type.startswith('list:reference'): | |
| return B('fk') | |
| else: | |
| return ' ' | |
| def type_repr(field): | |
| result = field.type | |
| if 'reference' in field.type: | |
| result = field.type.replace('reference ', '--> ') | |
| if field.name.endswith('_id') and field.name[:-3]==result[len('--> '):] : | |
| result = '--> ' | |
| return result | |
| # This is horribe HTML but the only one graphiz understands | |
| rows = [] | |
| cellpadding = 4 | |
| color = "#000000" | |
| bgcolor = "#FFFFFF" | |
| face = "Helvetica" | |
| face_bold = "Helvetica Bold" | |
| border = 0 | |
| rows.append(TR(TD(FONT(table, _face=face_bold, _color='blue'), # _size="20" doesn't work.. | |
| _colspan=3, _cellpadding=cellpadding, | |
| _align="center", _bgcolor=bgcolor))) | |
| for row in db[table]: | |
| if is_interesting_field( row.name +" "+ row.type +" "+ str(types(row)) ): | |
| rows.append(TR(TD(FONT(row.name, _color=color, _face=face_bold), | |
| _align="left", _cellpadding=cellpadding, | |
| _border=border), | |
| TD(FONT(type_repr(row), _color=color, _face=face), | |
| _align="left", _cellpadding=cellpadding, | |
| _border=border), | |
| TD(FONT(types(row), _color=color, _face=face), | |
| _align="center", _cellpadding=cellpadding, | |
| _border=border))) | |
| return "< %s >" % TABLE(*rows, **dict(_bgcolor=bgcolor, _border=1, | |
| _cellborder=0, _cellspacing=0) | |
| ).xml() | |
| graph_view=""" | |
| {{if request.function=='graph_model':}} | |
| <h2>{{=T("Graph Model")}}</h2> | |
| {{if not pgv:}} | |
| {{=T('pygraphviz library not found')}} | |
| {{elif not databases:}} | |
| {{=T("No databases in this application")}} | |
| {{else:}} | |
| <div class="btn-group"> | |
| <a class="btn dropdown-toggle" data-toggle="dropdown" href="#"> | |
| <i class="icon-download"></i> {{=T('Save model as...')}} | |
| <span class="caret"></span> | |
| </a> | |
| <ul class="dropdown-menu"> | |
| <li><a href="{{=URL('appadmin', 'bg_graph_model', args=['png'], vars=request.vars)}}">png</a></li> | |
| <li><a href="{{=URL('appadmin', 'bg_graph_model', args=['svg'], vars=request.vars)}}">svg</a></li> | |
| <li><a href="{{=URL('appadmin', 'bg_graph_model', args=['pdf'], vars=request.vars)}}">pdf</a></li> | |
| <li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'], vars=request.vars)}}">ps</a></li> | |
| <li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'], vars=request.vars)}}">dot</a></li> | |
| </ul> | |
| </div> | |
| <br /> | |
| {{=IMG(_src=URL('appadmin', 'bg_graph_model', vars=request.vars))}} | |
| {{pass}} | |
| {{pass}} | |
| """ | |
| def is_interesting_field( fieldname ): | |
| show_fields=(request.vars.show_fields or '').replace('%20', ' ').split() | |
| if not show_fields: return True | |
| for word in show_fields: | |
| if word in fieldname: | |
| return True # include | |
| if word.startswith('-') and word[1:] in fieldname: | |
| return False # or exclude | |
| def is_important_force_exceptions_first(tablename): # DEPRECATED | |
| # in views/appadmin.html forward vars=request.vars: =IMG(_src=URL('appadmin', 'bg_graph_model', vars=request.vars) | |
| # graph_model?table_filters=...&field_filters=...&show_fields=fk%20pk | |
| table_filters=(request.vars.table_filters or 'invoice sales_order -blind -good -batch -discount -shipment').replace('%20', ' ').split() | |
| field_filters=(request.vars.field_filters or 'user').replace('%20', ' ').split() | |
| # if request.vars.filters: | |
| # filters=request.vars.filters.split() | |
| # match by table name | |
| excluding_filters = [word[1:] for word in table_filters if word.startswith('-')] | |
| for word in excluding_filters: | |
| if word in tablename: | |
| return False # force exclude first | |
| for word in table_filters: | |
| if word in tablename: | |
| return True # include | |
| # match by field name | |
| for field in db[tablename]: | |
| for word in field_filters: # or one of it's fields' names | |
| if word in field.name: | |
| return True | |
| def is_important(tablename): | |
| # in views/appadmin.html forward vars=request.vars: =IMG(_src=URL('appadmin', 'bg_graph_model', vars=request.vars) | |
| # graph_model?table_filters=...&field_filters=... | |
| table_filters=(request.vars.table_filters or '-sales_order_good_ sales_order_good -blind -good -batch -discount -shipment invoice sales_order').replace('%20', ' ').split() | |
| field_filters=(request.vars.field_filters or request.vars.table_filters or 'pk fk').replace('%20', ' ').split() | |
| # if request.vars.filters: | |
| # filters=request.vars.filters.split() | |
| for word in table_filters: | |
| if word in tablename: | |
| return True # include | |
| if word.startswith('-') and word[1:] in tablename: | |
| return False # or exclude | |
| # match by field name | |
| for field in db[tablename]: | |
| for word in field_filters: # or one of it's fields' names | |
| if word in field.name: | |
| return True # include | |
| if word.startswith('-') and word[1:] in field.name: | |
| return False # or exclude | |
| def bg_graph_model(): | |
| graph = pgv.AGraph(layout='dot', directed=True, strict=False, rankdir='LR') | |
| subgraphs = dict() | |
| for tablename in db.tables: | |
| if hasattr(db[tablename],'_meta_graphmodel'): | |
| meta_graphmodel = db[tablename]._meta_graphmodel | |
| else: | |
| meta_graphmodel = dict(group=request.application, color='#ECECEC') | |
| group = meta_graphmodel['group'].replace(' ', '') | |
| if not subgraphs.has_key(group): | |
| subgraphs[group] = dict(meta=meta_graphmodel, tables=[]) | |
| subgraphs[group]['tables'].append(tablename) | |
| else: | |
| subgraphs[group]['tables'].append(tablename) | |
| graph.add_node(tablename, name=tablename, shape='plaintext', | |
| label=table_template(tablename) | |
| if is_important(tablename) else tablename | |
| ) | |
| for n, key in enumerate(subgraphs.iterkeys()): | |
| graph.subgraph(nbunch=subgraphs[key]['tables'], | |
| name='cluster%d' % n, | |
| style='filled', | |
| color=subgraphs[key]['meta']['color'], | |
| label=subgraphs[key]['meta']['group']) | |
| important_tables = set([]) | |
| for tablename in db.tables: | |
| for field in db[tablename]: | |
| f_type = field.type | |
| if isinstance(f_type,str) and ( | |
| f_type.startswith('reference') or | |
| f_type.startswith('list:reference')): | |
| referenced_table = f_type.split()[1].split('.')[0] | |
| n1 = graph.get_node(tablename) | |
| n2 = graph.get_node(referenced_table) | |
| if request.vars.neighbours=='0': # show only filtered, &neighbours=0 | |
| if is_important(tablename) : important_tables.add( tablename ) | |
| if is_important(referenced_table) : important_tables.add( referenced_table ) | |
| if is_important(tablename) and is_important(referenced_table): | |
| graph.add_edge(n1, n2, color="#4C4C4C", label='') | |
| else: # default: show neighbours | |
| if is_important(tablename) or is_important(referenced_table): | |
| important_tables.add( tablename ) | |
| important_tables.add( referenced_table ) | |
| graph.add_edge(n1, n2, color="#4C4C4C", label='') | |
| # import rpdb2; rpdb2.start_embedded_debugger("a") | |
| # from gluon.debug import dbg; dbg.set_trace() # stop here | |
| for tablename in db.tables: | |
| if not tablename in important_tables: | |
| graph.delete_node( tablename ) | |
| graph.layout() | |
| if not request.args: | |
| # response.headers['Content-Type'] = 'image/png' | |
| # return graph.draw(format='png', prog='dot') | |
| response.headers['Content-Type'] = 'image/svg+xml' | |
| return graph.draw(format='svg', prog='dot') | |
| else: | |
| response.headers['Content-Disposition']='attachment;filename=graph.%s'%request.args(0) | |
| if request.args(0) == 'dot': | |
| return graph.string() | |
| else: | |
| return graph.draw(format=request.args(0), prog='dot') | |
| # src= https://gist.github.com/dz0/ef4bea4e6f4aaf21f084c06190efecf6 | |
| def graph_model(): | |
| return dict(databases=databases, pgv=pgv) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment