Code


Version 8 (modified by Antonio Cavedoni <antonio@…>, 8 years ago) (diff)

Added model viz for the Zyons project, edited code to support GenericRelations and OneToOneFields

Converting Django models into Graphviz DOT files

Inspired by 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:

You might also be interested in this Django app by Andrew Barilla from which I borrowed some ideas, that displays the graphviz results directly from the web.

#!/usr/bin/python
"""Django model to DOT (Graphviz) converter
by Antonio Cavedoni <antonio@cavedoni.org>

Make sure your DJANGO_SETTINGS_MODULE is set to your project and call 
the script like this:

  $ python modelviz.py <app_label> > <filename>.dot

Example:

  $ python modelviz.py camera > foo.dot
"""

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__))

      # members
      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__))

      if o._meta.one_to_one_field:
         for field in o._meta.one_to_one_field:
            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)

      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)

      if o._meta.one_to_one_field:
         for field in o._meta.one_to_one_field:
            if 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)

      print "\n".join(rel)

   print "}"

if __name__ == "__main__":
   import sys
   app_label = sys.argv[1]
   generate_dot(app_label)

Attachments (12)

Download all attachments as: .zip