| 28 | | Make sure your DJANGO_SETTINGS_MODULE is set to your project and call |
| 29 | | the script like this: |
| 30 | | |
| 31 | | $ python modelviz.py <app_label> > <filename>.dot |
| 32 | | |
| 33 | | Changelog |
| 34 | | |
| 35 | | 0.5.1 |
| 36 | | Got rid of print statements, now the generate_dot() function returns |
| 37 | | a string with the file contents |
| 38 | | |
| 39 | | 0.5 |
| 40 | | Cleaned up code, now the relationship arrows start from the |
| 41 | | correct model attribute position |
| 42 | | |
| 43 | | 0.4 |
| 44 | | Fixed OneToOneField support (thanks, limodou) |
| 45 | | |
| 46 | | 0.3 |
| 47 | | Added support for GenericRelation and OneToOneField |
| 48 | | |
| 49 | | 0.2 |
| 50 | | Changed display (shape="record", thanks Malcolm Tredinnick), |
| 51 | | fixed arrow direction, added display of model attributes |
| 52 | | (thanks, Russell Keith-Magee) |
| 53 | | |
| 54 | | 0.1 |
| 55 | | First release. |
| 56 | | """ |
| 57 | | |
| 58 | | __version__ = "0.5.1" |
| 59 | | __svnid__ = "$Id: modelviz.py 4 2006-08-06 19:48:42Z verbosus $" |
| 60 | | __license__ = "Python" |
| 61 | | __author__ = "Antonio Cavedoni <http://cavedoni.com/>" |
| 62 | | __contributors__ = [ |
| 63 | | "Stefano J. Attardi <http://attardi.org/>", |
| 64 | | "limodou <http://www.donews.net/limodou/>" |
| 65 | | ] |
| 66 | | |
| 67 | | from django.db import models |
| 68 | | from django.db.models import get_models |
| 69 | | from django.db.models.fields.related import \ |
| 70 | | ForeignKey, OneToOneField, ManyToManyField |
| 71 | | from django.db.models.fields.generic import GenericRelation |
| 72 | | |
| 73 | | def generate_dot(app_label): |
| 74 | | app = models.get_app(app_label) |
| 75 | | |
| 76 | | graph = [] |
| 77 | | graph.append("digraph %s {" % ('"' + app.__name__ + '"')) |
| 78 | | graph.append(""" fontname = "Helvetica" |
| 79 | | fontsize = 8 |
| 80 | | |
| 81 | | node [ |
| 82 | | fontname = "Helvetica" |
| 83 | | fontsize = 8 |
| 84 | | shape = "record" |
| 85 | | ] |
| 86 | | edge [ |
| 87 | | fontname = "Helvetica" |
| 88 | | fontsize = 8 |
| 89 | | ] |
| 90 | | """) |
| 91 | | for o in get_models(app): |
| 92 | | graph.append(""" subgraph cluster_%(model)s { |
| 93 | | shape = "record"; |
| 94 | | label = "%(model)s"; |
| 95 | | fontname = "Helvetica Bold"; |
| 96 | | fontsize = 10; |
| 97 | | labelfontcolor = "black"; |
| 98 | | %(model)s [label = "{""" % {'model': o.__name__}) |
| 99 | | |
| 100 | | # model attributes |
| 101 | | def add_attributes(): |
| 102 | | graph.append("<%(model)s_%(field)s>%(field)s : %(related)s|" % \ |
| 103 | | {'model': o.__name__, 'field': field.name, |
| 104 | | 'related': type(field).__name__}) |
| 105 | | |
| 106 | | for field in o._meta.fields: |
| 107 | | add_attributes() |
| 108 | | |
| 109 | | if o._meta.many_to_many: |
| 110 | | for field in o._meta.many_to_many: |
| 111 | | add_attributes() |
| 112 | | |
| 113 | | graph.append(""" }"] [color="white" shape="record"];\n }\n""") |
| 114 | | |
| 115 | | # relations |
| 116 | | rel = [] |
| 117 | | def add_relation(extras=""): |
| 118 | | _rel = """ %(model)s:%(model)s_%(field)s -> %(related)s |
| 119 | | [label="%(relationship)s"] %(extras)s;\n""" % { |
| 120 | | 'model': o.__name__, 'field': field.name, |
| 121 | | 'related': field.rel.to.__name__, |
| 122 | | 'relationship': type(field).__name__, |
| 123 | | 'extras': extras} |
| 124 | | if _rel not in rel: |
| 125 | | rel.append(_rel) |
| 126 | | |
| 127 | | for field in o._meta.fields: |
| 128 | | if isinstance(field, ForeignKey): |
| 129 | | add_relation() |
| 130 | | elif isinstance(field, OneToOneField): |
| 131 | | add_relation("[arrowhead=none arrowtail=none]") |
| 132 | | |
| 133 | | if o._meta.many_to_many: |
| 134 | | for field in o._meta.many_to_many: |
| 135 | | if isinstance(field, ManyToManyField): |
| 136 | | add_relation("[arrowhead=normal arrowtail=normal]") |
| 137 | | elif isinstance(field, GenericRelation): |
| 138 | | add_relation( |
| 139 | | '[style="dotted"] [arrowhead=normal arrowtail=normal]') |
| 140 | | graph.append("".join(rel)) |
| 141 | | |
| 142 | | graph.append('}') |
| 143 | | return "".join(graph) |
| 144 | | |
| 145 | | if __name__ == "__main__": |
| 146 | | import sys |
| 147 | | app_label = sys.argv[1] |
| 148 | | print generate_dot(app_label) |
| 149 | | }}} |
| 150 | | |
| 151 | | = Examples = |
| 152 | | |
| 153 | | Camera |
| | 13 | === Camera website (yet unpublished) === |
| 167 | | = Feedback = |
| 168 | | * favo: I have a large app(some model has lots fields). The generated png file is too large. Maybe this tools could work in a concision mode which only contain related field and omit other fields of a model. |
| 169 | | * elvstone: How did you manage to get the edges to only reach the edge of the subgraphs? I get |
| 170 | | {{{ |
| 171 | | #!html |
| 172 | | <a href="http://bob.dose.se/watchtower.png">this</a> |
| 173 | | }}} |
| 174 | | result, which isn't very nice. I've digged through the GraphViz docs/mailing lists without luck :( |
| | 27 | === Other examples === |
| | 28 | |
| | 29 | * [http://zyons.com/ Zyons project] |
| | 30 | * Graphviz DOT files for the Zyons project: [http://cavedoni.com/2006/08/zyons-comment.dot comment] [http://cavedoni.com/2006/08/zyons-event.dot event] [http://cavedoni.com/2006/08/zyons-forum.dot forum] [http://cavedoni.com/2006/08/zyons-openid.dot openid] [http://cavedoni.com/2006/08/zyons-prefs.dot prefs] [http://cavedoni.com/2006/08/zyons-sessions.dot sessions] [http://cavedoni.com/2006/08/zyons-tag.dot tag] |
| | 31 | * Resulting graphs in PDF: [http://cavedoni.com/2006/08/zyons-comment.pdf comment] [http://cavedoni.com/2006/08/zyons-event.pdf event] [http://cavedoni.com/2006/08/zyons-forum.pdf forum] [http://cavedoni.com/2006/08/zyons-openid.pdf openid] [http://cavedoni.com/2006/08/zyons-prefs.pdf prefs] [http://cavedoni.com/2006/08/zyons-sessions.pdf sessions] [http://cavedoni.com/2006/08/zyons-tag.pdf tag] |
| | 32 | |
| | 33 | == Other References == |
| | 34 | |
| | 35 | You might also be interested in [http://www.exit66.com/diagram.zip this Django app by Andrew Barilla ] from which I borrowed some ideas, that displays the graphviz results directly from the web. |
| | 36 | |
| | 37 | == Feedback == |
| | 38 | |
| | 39 | Please direct all feedback to [mailto:antonio@cavedoni.org Antonio Cavedoni]. |