1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 | import yapgvb
from django.db.models.fields.related import OneToOneRel, ManyToManyRel, ManyToOneRel
class Diagram:
_graph = None
_models = []
_relationships = []
_is_built = False
def __init__(self, title='Django Model ERD'):
self._graph = yapgvb.Digraph(title)
def get_graph(self):
return self._graph;
def add_model(self, model):
self._models.append(model)
# get relationships
for field in model._meta.fields:
if field.rel:
self.add_relationship(model, field)
# m2m relationships
for field in model._meta.local_many_to_many:
self.add_relationship(model, field)
def remove_model(self, model):
try:
del self._models[model]
except IndexError:
pass
def add_relationship(self, model, field):
self._relationships.append((model,field))
def render(self, format='png', engine='dot'):
self._build()
self._graph.layout(engine)
file = '/tmp/graph.%s' % format
self._graph.render(file, format=format)
content = open(file, 'r').read()
import os; os.remove(file)
return content
def _build(self):
if self._is_built:
return
nodes = {}
for model in self._models:
name = model.__name__
label = model.__name__
nodes[name] = self._graph.add_node(name, label=label, shape='record')
for model, field in self._relationships:
if nodes.get(field.rel.to.__name__):
edge = self._graph.add_edge(nodes.get(model.__name__), nodes.get(field.rel.to.__name__))
edge.arrowhead, edge.arrowtail = self._get_arrow(model, field)
edge.minlen = 2
def _get_arrow(self, model, field):
map = {
'many' : 'crow',
'one' : 'tee',
'required' : 'tee',
'optional' : 'odot',
}
# get cardinality and modality
if type(field.rel) == OneToOneRel:
cardinality = ('one', 'one')
elif type(field.rel) == ManyToOneRel:
cardinality = ('one', 'many')
elif type(field.rel) == ManyToManyRel:
cardinality = ('many', 'many')
# :KLUDGE: we're just guessing the most likely case for modality here
if field.blank or type(field.rel) == ManyToManyRel:
modality = ('optional', 'optional')
else:
modality = ('required', 'optional')
return (map[cardinality[0]] + map[modality[0]],
map[cardinality[1]] + map[modality[1]])
## USAGE ##
d = Diagram()
d.add_model(User, Group)
d.render()
|
Comments
I am not sure I know what it can do. Can you add links to screenshots?
#
This is pretty clever. The usage fails with two parameters, but the class works super sweet for simple ERD diagrams. Thanks for posting.
#
Worth mentioning this command extension related to this: http://code.google.com/p/django-command-extensions/wiki/GraphModels
#