#!/usr/bin/env python """Django model to DOT (Graphviz) converter by Antonio Cavedoni 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] ... > .dot $ dot .dot -Tpng -o .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: modelviz.py 78 2007-07-15 19:04:47Z verbosus $" __license__ = "Python" __author__ = "Antonio Cavedoni " __contributors__ = [ "Stefano J. Attardi ", "limodou ", "Carlo C8E Miron", "Andre Campos ", "Justin Findlay ", ] import getopt import sys from django.core.management import setup_environ try: from . import settings except ImportError: pass else: setup_environ(settings) from django.db import models from django.db.models import get_models from django.db.models.fields.related import (ForeignKey, ManyToManyField, OneToOneField) from django.template import Context, Template 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=<
{{ relation.target }}
>] {{ model.name }} -> {{ relation.target }} [label="{{ relation.name }}"] {{ relation.arrows }}; {% endfor %} {% endfor %} {% for model in models %} {{ model.name }} [label=< {% if not disable_fields %} {% for field in model.fields %} {% endfor %} {% endif %}
{{ model.name }}
{{ field.name }} {{ field.type }}
>] {% 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': f'"{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 as 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()