1 | #!/usr/bin/env python |
---|
2 | """Django model to DOT (Graphviz) converter |
---|
3 | by Antonio Cavedoni <antonio@cavedoni.org> |
---|
4 | |
---|
5 | Make sure your DJANGO_SETTINGS_MODULE is set to your project and call |
---|
6 | the script like this: |
---|
7 | |
---|
8 | $ python modelviz.py <app_label> > <filename>.dot |
---|
9 | """ |
---|
10 | |
---|
11 | __version__ = "0.6" |
---|
12 | __svnid__ = "$Id$" |
---|
13 | __license__ = "Python" |
---|
14 | __author__ = "Antonio Cavedoni <http://cavedoni.com/>" |
---|
15 | __contributors__ = [ |
---|
16 | "Stefano J. Attardi <http://attardi.org/>", |
---|
17 | "limodou <http://www.donews.net/limodou/>", |
---|
18 | "Carlo C8E Miron" |
---|
19 | ] |
---|
20 | |
---|
21 | from django.db import models |
---|
22 | from django.db.models import get_models |
---|
23 | from django.db.models.fields.related import \ |
---|
24 | ForeignKey, OneToOneField, ManyToManyField |
---|
25 | from django.contrib.contenttypes.generic import GenericRelation |
---|
26 | from django.template import Template, Context |
---|
27 | |
---|
28 | dot_template = """ |
---|
29 | digraph {{ name }} { |
---|
30 | fontname = "Helvetica" |
---|
31 | fontsize = 8 |
---|
32 | |
---|
33 | node [ |
---|
34 | fontname = "Helvetica" |
---|
35 | fontsize = 8 |
---|
36 | shape = "plaintext" |
---|
37 | ] |
---|
38 | edge [ |
---|
39 | fontname = "Helvetica" |
---|
40 | fontsize = 8 |
---|
41 | ] |
---|
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 | |
---|
66 | def 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 | } |
---|
79 | |
---|
80 | # model attributes |
---|
81 | def add_attributes(): |
---|
82 | model['fields'].append({ |
---|
83 | 'name': field.name, |
---|
84 | 'type': type(field).__name__ |
---|
85 | }) |
---|
86 | |
---|
87 | for field in appmodel._meta.fields: |
---|
88 | add_attributes() |
---|
89 | |
---|
90 | if appmodel._meta.many_to_many: |
---|
91 | for field in appmodel._meta.many_to_many: |
---|
92 | add_attributes() |
---|
93 | |
---|
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) |
---|
103 | |
---|
104 | for field in appmodel._meta.fields: |
---|
105 | if isinstance(field, ForeignKey): |
---|
106 | add_relation() |
---|
107 | elif isinstance(field, OneToOneField): |
---|
108 | add_relation("[arrowhead=none arrowtail=none]") |
---|
109 | |
---|
110 | if appmodel._meta.many_to_many: |
---|
111 | for field in appmodel._meta.many_to_many: |
---|
112 | if isinstance(field, ManyToManyField): |
---|
113 | add_relation("[arrowhead=normal arrowtail=normal]") |
---|
114 | elif isinstance(field, GenericRelation): |
---|
115 | add_relation( |
---|
116 | '[style="dotted"] [arrowhead=normal arrowtail=normal]') |
---|
117 | graph['models'].append(model) |
---|
118 | |
---|
119 | t = Template(dot_template) |
---|
120 | return t.render(graph) |
---|
121 | |
---|
122 | if __name__ == "__main__": |
---|
123 | import sys |
---|
124 | try: |
---|
125 | app_label = sys.argv[1] |
---|
126 | print generate_dot(app_label) |
---|
127 | except IndexError: |
---|
128 | print __doc__ |
---|