web/lib/django_extensions/management/modelviz.py
author ymh <ymh.work@gmail.com>
Wed, 20 Jan 2010 12:37:40 +0100
changeset 3 526ebd3988b0
permissions -rw-r--r--
replace pocketfilms occurence by blinkster
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
3
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
     1
#!/usr/bin/env python
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
     2
"""Django model to DOT (Graphviz) converter
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
     3
by Antonio Cavedoni <antonio@cavedoni.org>
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
     4
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
Make sure your DJANGO_SETTINGS_MODULE is set to your project or
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
place this script in the same directory of the project and call
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
     7
the script like this:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
     8
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
$ python modelviz.py [-h] [-a] [-d] [-g] [-i <model_names>] <app_label> ... <app_label> > <filename>.dot
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    10
$ dot <filename>.dot -Tpng -o <filename>.png
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    11
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    12
options:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    13
    -h, --help
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    14
    show this help message and exit.
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    15
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    16
    -a, --all_applications
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    17
    show models from all applications.
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    18
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    19
    -d, --disable_fields
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    20
    don't show the class member fields.
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    21
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    22
    -g, --group_models
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    23
    draw an enclosing box around models from the same app.
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    24
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    25
    -i, --include_models=User,Person,Car
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    26
    only include selected models in graph.
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    27
"""
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    28
__version__ = "0.9"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    29
__svnid__ = "$Id$"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    30
__license__ = "Python"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    31
__author__ = "Antonio Cavedoni <http://cavedoni.com/>"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    32
__contributors__ = [
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    33
   "Stefano J. Attardi <http://attardi.org/>",
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    34
   "limodou <http://www.donews.net/limodou/>",
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    35
   "Carlo C8E Miron",
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    36
   "Andre Campos <cahenan@gmail.com>",
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    37
   "Justin Findlay <jfindlay@gmail.com>",
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    38
   "Alexander Houben <alexander@houben.ch>",
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    39
   "Bas van Oostveen <v.oostveen@gmail.com>",
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    40
]
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    41
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    42
import getopt, sys
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    43
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    44
from django.core.management import setup_environ
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    45
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    46
try:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    47
    import settings
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    48
except ImportError:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    49
    pass
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    50
else:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    51
    setup_environ(settings)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    52
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    53
from django.utils.safestring import mark_safe
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    54
from django.template import Template, Context
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    55
from django.db import models
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    56
from django.db.models import get_models
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    57
from django.db.models.fields.related import \
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    58
    ForeignKey, OneToOneField, ManyToManyField
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    59
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    60
try:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    61
    from django.db.models.fields.generic import GenericRelation
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    62
except ImportError:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    63
    from django.contrib.contenttypes.generic import GenericRelation
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    64
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    65
head_template = """
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    66
digraph name {
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    67
  fontname = "Helvetica"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    68
  fontsize = 8
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    69
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    70
  node [
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    71
    fontname = "Helvetica"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    72
    fontsize = 8
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    73
    shape = "plaintext"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    74
  ]
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    75
  edge [
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    76
    fontname = "Helvetica"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    77
    fontsize = 8
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    78
  ]
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    79
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    80
"""
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    81
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    82
body_template = """
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    83
{% if use_subgraph %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    84
subgraph {{ cluster_app_name }} {
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    85
  label=<
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    86
        <TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0">
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    87
        <TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    88
        ><FONT FACE="Helvetica Bold" COLOR="Black" POINT-SIZE="12"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    89
        >{{ app_name }}</FONT></TD></TR>
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    90
        </TABLE>
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    91
        >
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    92
  color=olivedrab4
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    93
  style="rounded"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    94
{% endif %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    95
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    96
  {% for model in models %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    97
    {{ model.app_name }}_{{ model.name }} [label=<
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    98
    <TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
    99
     <TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   100
     ><FONT FACE="Helvetica Bold" COLOR="white"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   101
     >{{ model.name }}{% if model.abstracts %}<BR/>&lt;<FONT FACE="Helvetica Italic">{{ model.abstracts|join:"," }}</FONT>&gt;{% endif %}</FONT></TD></TR>
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   102
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   103
    {% if not disable_fields %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   104
        {% for field in model.fields %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   105
        <TR><TD ALIGN="LEFT" BORDER="0"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   106
        ><FONT {% if field.blank %}COLOR="#7B7B7B" {% endif %}FACE="Helvetica {% if field.abstract %}Italic{% else %}Bold{% endif %}">{{ field.name }}</FONT
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   107
        ></TD>
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   108
        <TD ALIGN="LEFT"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   109
        ><FONT {% if field.blank %}COLOR="#7B7B7B" {% endif %}FACE="Helvetica {% if field.abstract %}Italic{% else %}Bold{% endif %}">{{ field.type }}</FONT
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   110
        ></TD></TR>
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   111
        {% endfor %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   112
    {% endif %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   113
    </TABLE>
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   114
    >]
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   115
  {% endfor %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   116
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   117
{% if use_subgraph %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   118
}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   119
{% endif %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   120
"""
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   121
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   122
rel_template = """
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   123
  {% for model in models %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   124
    {% for relation in model.relations %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   125
    {% if relation.needs_node %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   126
    {{ relation.target_app }}_{{ relation.target }} [label=<
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   127
        <TABLE BGCOLOR="palegoldenrod" BORDER="0" CELLBORDER="0" CELLSPACING="0">
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   128
        <TR><TD COLSPAN="2" CELLPADDING="4" ALIGN="CENTER" BGCOLOR="olivedrab4"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   129
        ><FONT FACE="Helvetica Bold" COLOR="white"
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   130
        >{{ relation.target }}</FONT></TD></TR>
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   131
        </TABLE>
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   132
        >]
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   133
    {% endif %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   134
    {{ model.app_name }}_{{ model.name }} -> {{ relation.target_app }}_{{ relation.target }}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   135
    [label="{{ relation.name }}"] {{ relation.arrows }};
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   136
    {% endfor %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   137
  {% endfor %}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   138
"""
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   139
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   140
tail_template = """
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   141
}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   142
"""
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   143
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   144
def generate_dot(app_labels, **kwargs):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   145
    disable_fields = kwargs.get('disable_fields', False)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   146
    include_models = kwargs.get('include_models', [])
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   147
    all_applications = kwargs.get('all_applications', False)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   148
    use_subgraph = kwargs.get('group_models', False)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   149
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   150
    dot = head_template
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   151
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   152
    apps = []
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   153
    if all_applications:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   154
        apps = models.get_apps()
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   155
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   156
    for app_label in app_labels:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   157
        app = models.get_app(app_label)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   158
        if not app in apps:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   159
            apps.append(app)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   160
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   161
    graphs = []
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   162
    for app in apps:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   163
        graph = Context({
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   164
            'name': '"%s"' % app.__name__,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   165
            'app_name': "%s" % '.'.join(app.__name__.split('.')[:-1]),
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   166
            'cluster_app_name': "cluster_%s" % app.__name__.replace(".", "_"),
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   167
            'disable_fields': disable_fields,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   168
            'use_subgraph': use_subgraph,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   169
            'models': []
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   170
        })
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   171
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   172
        for appmodel in get_models(app):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   173
            abstracts = [e.__name__ for e in appmodel.__bases__ if hasattr(e, '_meta') and e._meta.abstract]
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   174
            abstract_fields = []
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   175
            for e in appmodel.__bases__:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   176
                if hasattr(e, '_meta') and e._meta.abstract:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   177
                    abstract_fields.extend(e._meta.fields)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   178
            model = {
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   179
                'app_name': app.__name__.replace(".", "_"),
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   180
                'name': appmodel.__name__,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   181
                'abstracts': abstracts,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   182
                'fields': [],
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   183
                'relations': []
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   184
            }
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   185
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   186
            # consider given model name ?
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   187
            def consider(model_name):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   188
                return not include_models or model_name in include_models
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   189
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   190
            if not consider(appmodel._meta.object_name):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   191
                continue
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   192
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   193
            # model attributes
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   194
            def add_attributes(field):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   195
                model['fields'].append({
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   196
                    'name': field.name,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   197
                    'type': type(field).__name__,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   198
                    'blank': field.blank,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   199
                    'abstract': field in abstract_fields,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   200
                })
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   201
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   202
            for field in appmodel._meta.fields:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   203
                add_attributes(field)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   204
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   205
            if appmodel._meta.many_to_many:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   206
                for field in appmodel._meta.many_to_many:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   207
                    add_attributes(field)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   208
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   209
            # relations
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   210
            def add_relation(field, extras=""):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   211
                _rel = {
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   212
                    'target_app': field.rel.to.__module__.replace('.','_'),
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   213
                    'target': field.rel.to.__name__,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   214
                    'type': type(field).__name__,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   215
                    'name': field.name,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   216
                    'arrows': extras,
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   217
                    'needs_node': True
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   218
                }
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   219
                if _rel not in model['relations'] and consider(_rel['target']):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   220
                    model['relations'].append(_rel)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   221
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   222
            for field in appmodel._meta.fields:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   223
                if isinstance(field, ForeignKey):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   224
                    add_relation(field)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   225
                elif isinstance(field, OneToOneField):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   226
                    add_relation(field, '[arrowhead=none arrowtail=none]')
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   227
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   228
            if appmodel._meta.many_to_many:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   229
                for field in appmodel._meta.many_to_many:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   230
                    if isinstance(field, ManyToManyField) and getattr(field, 'creates_table', False):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   231
                        add_relation(field, '[arrowhead=normal arrowtail=normal]')
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   232
                    elif isinstance(field, GenericRelation):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   233
                        add_relation(field, mark_safe('[style="dotted"] [arrowhead=normal arrowtail=normal]'))
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   234
            graph['models'].append(model)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   235
        graphs.append(graph)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   236
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   237
    nodes = []
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   238
    for graph in graphs:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   239
        nodes.extend([e['name'] for e in graph['models']])
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   240
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   241
    for graph in graphs:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   242
        # don't draw duplication nodes because of relations
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   243
        for model in graph['models']:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   244
            for relation in model['relations']:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   245
                if relation['target'] in nodes:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   246
                    relation['needs_node'] = False
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   247
        # render templates
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   248
        t = Template(body_template)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   249
        dot += '\n' + t.render(graph)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   250
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   251
    for graph in graphs:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   252
        t = Template(rel_template)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   253
        dot += '\n' + t.render(graph)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   254
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   255
    dot += '\n' + tail_template
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   256
    return dot
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   257
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   258
def main():
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   259
    try:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   260
        opts, args = getopt.getopt(sys.argv[1:], "hadgi:",
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   261
                    ["help", "all_applications", "disable_fields", "group_models", "include_models="])
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   262
    except getopt.GetoptError, error:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   263
        print __doc__
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   264
        sys.exit(error)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   265
    
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   266
    kwargs = {}
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   267
    for opt, arg in opts:
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   268
        if opt in ("-h", "--help"):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   269
            print __doc__
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   270
            sys.exit()
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   271
        if opt in ("-a", "--all_applications"):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   272
            kwargs['all_applications'] = True
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   273
        if opt in ("-d", "--disable_fields"):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   274
            kwargs['disable_fields'] = True
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   275
        if opt in ("-g", "--group_models"):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   276
            kwargs['group_models'] = True
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   277
        if opt in ("-i", "--include_models"):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   278
            kwargs['include_models'] = arg.split(',')
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   279
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   280
    if not args and not kwargs.get('all_applications', False):
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   281
        print __doc__
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   282
        sys.exit()
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   283
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   284
    print generate_dot(args, **kwargs)
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   285
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   286
if __name__ == "__main__":
526ebd3988b0 replace pocketfilms occurence by blinkster
ymh <ymh.work@gmail.com>
parents:
diff changeset
   287
    main()