Changeset 51

Show
Ignore:
Timestamp:
11/01/06 21:38:57 (2 years ago)
Author:
verbosus
Message:

Modelviz 0.6: introduced colours, switched to Django templates for DOT generation, switched to DOT HTML-like tables for graph layout

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • django/trunk/utils/modelviz.py

    r38 r51  
    1 #!/usr/bin/python 
     1#!/usr/bin/env python 
    22"""Django model to DOT (Graphviz) converter 
    33by Antonio Cavedoni <antonio@cavedoni.org> 
     
    66the script like this: 
    77 
    8   $ python modelviz.py <app_label> > <filename>.dot 
    9  
    10 Changelog 
    11  
    12 0.5.1 
    13 Got rid of print statements, now the generate_dot() function returns 
    14 a string with the file contents 
    15  
    16 0.5 
    17 Cleaned up code, now the relationship arrows start from the  
    18 correct model attribute position 
    19  
    20 0.4 
    21 Fixed OneToOneField support (thanks, limodou) 
    22  
    23 0.3 
    24 Added support for GenericRelation and OneToOneField 
    25  
    26 0.2 
    27 Changed display (shape="record", thanks Malcolm Tredinnick),  
    28 fixed arrow direction, added display of model attributes  
    29 (thanks, Russell Keith-Magee) 
    30  
    31 0.1 
    32 First release. 
     8$ python modelviz.py <app_label> > <filename>.dot 
    339""" 
    3410 
    35 __version__ = "0.5.1" 
     11__version__ = "0.6" 
    3612__svnid__ = "$Id$" 
    3713__license__ = "Python" 
     
    3915__contributors__ = [ 
    4016   "Stefano J. Attardi <http://attardi.org/>", 
    41    "limodou <http://www.donews.net/limodou/>" 
     17   "limodou <http://www.donews.net/limodou/>", 
     18   "Carlo C8E Miron" 
    4219   ] 
    4320 
     
    4724    ForeignKey, OneToOneField, ManyToManyField 
    4825from django.db.models.fields.generic import GenericRelation 
     26from django.template import Template, Context 
    4927 
    50 def generate_dot(app_label): 
    51    app = models.get_app(app_label) 
     28dot_template = """ 
     29digraph {{ name }} { 
     30  fontname = "Helvetica" 
     31  fontsize = 8 
    5232 
    53    graph = [] 
    54    graph.append("digraph %s {" % ('"' + app.__name__ + '"')) 
    55    graph.append("""  fontname = "Helvetica" 
    56   fontsize = 8 
    57        
    5833  node [ 
    5934    fontname = "Helvetica" 
    6035    fontsize = 8 
    61     shape = "record" 
     36    shape = "plaintext" 
    6237  ] 
    6338   edge [ 
     
    6540    fontsize = 8 
    6641  ] 
    67 """) 
    68    for o in get_models(app): 
    69       graph.append(""" subgraph cluster_%(model)s { 
    70   shape = "record"; 
    71   label = "%(model)s"; 
    72   fontname = "Helvetica Bold"; 
    73   fontsize = 10; 
    74   labelfontcolor = "black"; 
    75   %(model)s [label = "{""" % {'model': o.__name__}) 
     42 
     43  {% for model in models %} 
     44  {{ model.name }} [label=< 
     45    <TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0"> 
     46     <TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4" 
     47     ><FONT FACE="Helvetica Bold" COLOR="white" 
     48     >{{ model.name }}</FONT></TD></TR> 
     49     {% for field in model.fields %} 
     50     <TR><TD ALIGN="LEFT" BORDER="0" 
     51     ><FONT FACE="Helvetica Bold">{{ field.name }}</FONT 
     52     ></TD> 
     53     <TD ALIGN="LEFT">{{ field.type }}</TD></TR> 
     54     {% endfor %} 
     55    </TABLE> 
     56    >] 
     57    
     58  {% for relation in model.relations %} 
     59  {{ model.name }} -> {{ relation.target }}  
     60    [label="{{ relation.type }}"] {{ relation.arrows }}; 
     61  {% endfor %} 
     62  {% endfor %} 
     63} 
     64""" 
     65 
     66def generate_dot(app_label): 
     67   app = models.get_app(app_label) 
     68   graph = Context({ 
     69      'name': '"%s"' % app.__name__,  
     70      'models': [] 
     71      }) 
     72 
     73   for appmodel in get_models(app): 
     74      model = { 
     75         'name': appmodel.__name__, 
     76         'fields': [], 
     77         'relations': [] 
     78         } 
    7679 
    7780      # model attributes 
    7881      def add_attributes(): 
    79          graph.append("<%(model)s_%(field)s>%(field)s : %(related)s|" % \ 
    80                       {'model': o.__name__, 'field': field.name,  
    81                        'related': type(field).__name__}) 
     82         model['fields'].append({ 
     83               'name': field.name, 
     84               'type': type(field).__name__ 
     85               }) 
    8286 
    83       for field in o._meta.fields: 
     87      for field in appmodel._meta.fields: 
    8488         add_attributes() 
    8589          
    86       if o._meta.many_to_many: 
    87          for field in o._meta.many_to_many: 
     90      if appmodel._meta.many_to_many: 
     91         for field in appmodel._meta.many_to_many: 
    8892            add_attributes() 
    8993 
    90       graph.append(""" }"] [color="white" shape="record"];\n }\n""") 
     94      # relations 
     95      def add_relation(extras=""): 
     96         _rel = { 
     97            'target': field.rel.to.__name__, 
     98            'type': type(field).__name__, 
     99            'arrows': extras 
     100            } 
     101         if _rel not in model['relations']: 
     102            model['relations'].append(_rel) 
    91103 
    92       # relations 
    93       rel = [] 
    94       def add_relation(extras=""): 
    95          _rel = """ %(model)s:%(model)s_%(field)s -> %(related)s  
    96          [label="%(relationship)s"] %(extras)s;\n""" % { 
    97             'model': o.__name__, 'field': field.name,  
    98             'related': field.rel.to.__name__,  
    99             'relationship': type(field).__name__, 
    100             'extras': extras} 
    101          if _rel not in rel: 
    102             rel.append(_rel) 
    103  
    104       for field in o._meta.fields: 
     104      for field in appmodel._meta.fields: 
    105105         if isinstance(field, ForeignKey): 
    106106            add_relation() 
     
    108108            add_relation("[arrowhead=none arrowtail=none]") 
    109109 
    110       if o._meta.many_to_many: 
    111          for field in o._meta.many_to_many: 
     110      if appmodel._meta.many_to_many: 
     111         for field in appmodel._meta.many_to_many: 
    112112            if isinstance(field, ManyToManyField): 
    113113               add_relation("[arrowhead=normal arrowtail=normal]") 
     
    115115               add_relation( 
    116116                  '[style="dotted"] [arrowhead=normal arrowtail=normal]') 
    117       graph.append("".join(rel)) 
    118  
    119    graph.append('}') 
    120    return "".join(graph) 
     117      graph['models'].append(model) 
     118    
     119   t = Template(dot_template) 
     120   return t.render(graph) 
    121121 
    122122if __name__ == "__main__": 
    123123   import sys 
    124    app_label = sys.argv[1] 
    125    print generate_dot(app_label) 
     124   try: 
     125      app_label = sys.argv[1] 
     126      print generate_dot(app_label) 
     127   except IndexError: 
     128      print __doc__