= Converting Django models into Graphviz DOT files =
Inspired by [http://www.hackdiary.com/archives/000093.html this nice hack by Matt Biddulph] I set out to create a similar thing for Django models. Below is an initial implementation, and here are some results generated with the OS X version of Graphviz:
* 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]
* 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]
* Other samples:
* [http://cavedoni.com/2006/08/camera-001.dot generated dot file]: resulting image in [http://cavedoni.com/2006/08/camera-001.pdf PDF],
{{{
#!html
PNG
}}}
* [http://cavedoni.com/2006/08/mincer-001.dot generated dot file]: resulting image in [http://cavedoni.com/2006/08/mincer-001.pdf PDF],
{{{
#!html
PNG
}}}
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.
{{{
#!python
#!/usr/bin/python
"""Django model to DOT (Graphviz) converter
by Antonio Cavedoni
Make sure your DJANGO_SETTINGS_MODULE is set to your project and call
the script like this:
$ python modelviz.py > .dot
Changelog
0.4
Fixed OneToOneField support (thanks, limodou)
0.3
Added support for GenericRelation and OneToOneField
0.2
Changed display (shape="record", thanks Malcolm Tredinnick),
fixed arrow direction, added display of model attributes
(thanks, Russell Keith-Magee)
0.1
First release.
"""
__version__ = "0.4"
__license__ = "Python"
__author__ = "Antonio Cavedoni ",
"limodou "
]
from django.db import models
from django.db.models import get_models
from django.db.models.fields.related import \
ForeignKey, OneToOneField, ManyToManyField
from django.db.models.fields.generic import GenericRelation
def generate_dot(app_label):
app = models.get_app(app_label)
print "digraph %s {" % ('"' + app.__name__ + '"')
print """ fontname = "Helvetica"
fontsize = 8
node [
fontname = "Helvetica"
fontsize = 8
shape = "record"
]
edge [
fontname = "Helvetica"
fontsize = 8
]
"""
for o in get_models(app):
nodes = []
nodes.append(""" %s [
label = "{%s |""" % (o.__name__, o.__name__))
# model attributes
for field in o._meta.fields:
nodes.append('%s : %s\\l' % (field.name, type(field).__name__))
if o._meta.many_to_many:
for field in o._meta.many_to_many:
nodes.append('%s : %s\\l' % (field.name, type(field).__name__))
nodes.append(""" }"\n]\n""")
print "".join(nodes)
# relations
rel = []
for field in o._meta.fields:
if isinstance(field, ForeignKey):
_rel = ' %s -> %s [label="%s"];' % \
(o.__name__, field.rel.to.__name__, type(field).__name__)
if _rel not in rel:
rel.append(_rel)
elif isinstance(field, OneToOneField):
_rel = ' %s -> %s [label="%s"] [arrowhead=none arrowtail=none];' % (o.__name__, field.rel.to.__name__, type(field).__name__)
if _rel not in rel:
rel.append(_rel)
for field in o._meta.fields:
if isinstance(field, ForeignKey):
_rel = ' %s -> %s [label="%s"];' % \
(o.__name__, field.rel.to.__name__, type(field).__name__)
if _rel not in rel:
rel.append(_rel)
if o._meta.many_to_many:
for field in o._meta.many_to_many:
if isinstance(field, ManyToManyField):
_rel = ' %s -> %s [label="%s"] [arrowhead=normal arrowtail=normal];' % \
(o.__name__, field.rel.to.__name__, type(field).__name__)
if _rel not in rel:
rel.append(_rel)
if isinstance(field, GenericRelation):
_rel = ' %s -> %s [label="%s"] [style="dotted"] [arrowhead=normal arrowtail=normal];' % \
(o.__name__, field.rel.to.__name__, type(field).__name__)
if _rel not in rel:
rel.append(_rel)
print "\n".join(rel)
print "}"
if __name__ == "__main__":
import sys
app_label = sys.argv[1]
generate_dot(app_label)
}}}