diff options
author | showard <showard@592f7852-d20e-0410-864c-8624ca9c26a4> | 2009-06-08 23:29:54 +0000 |
---|---|---|
committer | showard <showard@592f7852-d20e-0410-864c-8624ca9c26a4> | 2009-06-08 23:29:54 +0000 |
commit | 442812554b815827687368a302842f1013a295ac (patch) | |
tree | e2353a6fabc0d213fa13e8ddb38bc1a6bc24cc94 /contrib | |
parent | f6e0adf11be94295fcc9b8658aa983d37523a97c (diff) |
quick script to generate schema diagrams for AFE and TKO. should make it easier to keep the diagrams on the wiki up to date. including the open-source tool modelviz.py.
Signed-off-by: Steve Howard <showard@google.com>
git-svn-id: svn://test.kernel.org/autotest/trunk@3231 592f7852-d20e-0410-864c-8624ca9c26a4
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/modelviz.py | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/contrib/modelviz.py b/contrib/modelviz.py new file mode 100644 index 00000000..689a363d --- /dev/null +++ b/contrib/modelviz.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python +"""Django model to DOT (Graphviz) converter +by Antonio Cavedoni <antonio@cavedoni.org> + +Make sure your DJANGO_SETTINGS_MODULE is set to your project or +place this script in the same directory of the project and call +the script like this: + +$ python modelviz.py [-h] [-d] <app_label> ... <app_label> > <filename>.dot +$ dot <filename>.dot -Tpng -o <filename>.png + +options: + -h, --help + show this help message and exit. + + -d, --disable_fields + don't show the class member fields. +""" +__version__ = "0.8" +__svnid__ = "$Id$" +__license__ = "Python" +__author__ = "Antonio Cavedoni <http://cavedoni.com/>" +__contributors__ = [ + "Stefano J. Attardi <http://attardi.org/>", + "limodou <http://www.donews.net/limodou/>", + "Carlo C8E Miron", + "Andre Campos <cahenan@gmail.com>", + "Justin Findlay <jfindlay@gmail.com>", + ] + +import getopt, sys + +from django.core.management import setup_environ + +try: + import settings +except ImportError: + pass +else: + setup_environ(settings) + +from django.template import Template, Context +from django.db import models +from django.db.models import get_models +from django.db.models.fields.related import \ + ForeignKey, OneToOneField, ManyToManyField + +try: + from django.db.models.fields.generic import GenericRelation +except ImportError: + from django.contrib.contenttypes.generic import GenericRelation + +head_template = """ +digraph name { + fontname = "Helvetica" + fontsize = 8 + + node [ + fontname = "Helvetica" + fontsize = 8 + shape = "plaintext" + ] + edge [ + fontname = "Helvetica" + fontsize = 8 + ] + +""" + +body_template = """ + {% for model in models %} + {% for relation in model.relations %} + {{ relation.target }} [label=< + <TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0"> + <TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4" + ><FONT FACE="Helvetica Bold" COLOR="white" + >{{ relation.target }}</FONT></TD></TR> + </TABLE> + >] + {{ model.name }} -> {{ relation.target }} + [label="{{ relation.name }}"] {{ relation.arrows }}; + {% endfor %} + {% endfor %} + + {% for model in models %} + {{ model.name }} [label=< + <TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0"> + <TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4" + ><FONT FACE="Helvetica Bold" COLOR="white" + >{{ model.name }}</FONT></TD></TR> + + {% if not disable_fields %} + {% for field in model.fields %} + <TR><TD ALIGN="LEFT" BORDER="0" + ><FONT {% if field.blank %}COLOR="#7B7B7B" {% endif %}FACE="Helvetica Bold">{{ field.name }}</FONT + ></TD> + <TD ALIGN="LEFT" + ><FONT {% if field.blank %}COLOR="#7B7B7B" {% endif %}FACE="Helvetica Bold">{{ field.type }}</FONT + ></TD></TR> + {% endfor %} + {% endif %} + </TABLE> + >] + {% endfor %} +""" + +tail_template = """ +} +""" + +def generate_dot(app_labels, **kwargs): + disable_fields = kwargs.get('disable_fields', False) + + dot = head_template + + for app_label in app_labels: + app = models.get_app(app_label) + graph = Context({ + 'name': '"%s"' % app.__name__, + 'disable_fields': disable_fields, + 'models': [] + }) + + for appmodel in get_models(app): + model = { + 'name': appmodel.__name__, + 'fields': [], + 'relations': [] + } + + # model attributes + def add_attributes(): + model['fields'].append({ + 'name': field.name, + 'type': type(field).__name__, + 'blank': field.blank + }) + + for field in appmodel._meta.fields: + add_attributes() + + if appmodel._meta.many_to_many: + for field in appmodel._meta.many_to_many: + add_attributes() + + # relations + def add_relation(extras=""): + _rel = { + 'target': field.rel.to.__name__, + 'type': type(field).__name__, + 'name': field.name, + 'arrows': extras + } + if _rel not in model['relations']: + model['relations'].append(_rel) + + for field in appmodel._meta.fields: + if isinstance(field, ForeignKey): + add_relation() + elif isinstance(field, OneToOneField): + add_relation("[arrowhead=none arrowtail=none]") + + if appmodel._meta.many_to_many: + for field in appmodel._meta.many_to_many: + if isinstance(field, ManyToManyField): + add_relation("[arrowhead=normal arrowtail=normal]") + elif isinstance(field, GenericRelation): + add_relation( + '[style="dotted"] [arrowhead=normal arrowtail=normal]') + graph['models'].append(model) + + t = Template(body_template) + dot += '\n' + t.render(graph) + + dot += '\n' + tail_template + + return dot + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "hd", + ["help", "disable_fields"]) + except getopt.GetoptError, error: + print __doc__ + sys.exit(error) + else: + if not args: + print __doc__ + sys.exit() + + kwargs = {} + for opt, arg in opts: + if opt in ("-h", "--help"): + print __doc__ + sys.exit() + if opt in ("-d", "--disable_fields"): + kwargs['disable_fields'] = True + print generate_dot(args, **kwargs) + +if __name__ == "__main__": + main() |