neumond / django-dia Goto Github PK
View Code? Open in Web Editor NEWGenerate .dia diagram of your django project's models.
Generate .dia diagram of your django project's models.
Django-dia was derived from MIT-licensed code, but didn't specify explicit license for itself. I guess the best option would be to preserve existing MIT license. Therefore I'm asking all the contributors to approve this change, namely
@encolpe
@pauloxnet
@randomfish
Thank you!
I have "apps" dir for custom applications and I tried to generate schema for specified app by executing:
python manage.py make_diagram -e -o scheme apps.xparts
python manage.py make_diagram -e -o scheme xparts
and I received an error:
manage.py make_diagram: error: unrecognized arguments: xparts
or apps.xparts
Hi,
I've model like this
class AbstractClass(models.Model):
field = models.ForeignKey("related_field")
class Meta:
abstract = True
class RealClass(AbstractClass):
other_field = models.CharField()`
with django 11 get_relation_target_field() in utils.py raises exception
return target_model._meta.pk
AttributeError: 'unicode' object has no attribute '_meta'
This is labelled as # 1.8 compat, so I think someting wrong in previus
# newer django
if hasattr(rel_field, 'target_field'):
return rel_field.target_field
PS django-extensions fails too,
... ./django-dia/management/commands/make_diagram.py", line 64, in make_dia_attribute
value = u'#{}#'.format(value)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 9: ordinal not in range(128)
https://code.djangoproject.com/wiki/Dia2Django
There is high chance they're compatible, i.e. you can generate .dia from live app, then convert it back to models.py.
Currently only model exclusion list is implemented. It is a raw text file containing list of fully qualified model names (you can see possible names via -p
option). There's no way to specify background colors for apps and models, assign styles for arrows: you have to do this manually in dia and it can be very boring. Possible solution is configuration file, may be YAML, with all this data you'll fill during fune-tuning diagram output.
Current implementation places tables randomly leaving it to user to lay out manually everything in diagram. Arrows often become very long and entangled with each other.
Implementation should use something like multiple springs model: every arrow is a spring and tries to be as short as possible. That way relevant tables will be placed near each other.
Since I don't have much time right now, here is a quick patch that made django-dia work with python 3.4 for me. Most of the patch is actually pep8 reformatting that my vim does automatically, sorry for that.
Once I have a bit more time I'll explore these changes a bit further and try to create a proper pull request, but for now this might be a good starting point for anyone looking for dia-file creation from django models in python3 projects.
--- venv27_D18/lib/python2.7/site-packages/django-dia/management/commands/make_diagram.py.orig 2015-08-23 23:35:24.992012483 +0200
+++ venv34_D18/lib/python3.4/site-packages/django-dia/management/commands/make_diagram.py 2015-08-24 00:11:08.794872262 +0200
@@ -60,7 +60,7 @@
if atype == 'boolean':
value = 'true' if value else 'false'
elif atype == 'string':
- value = u'#{}#'.format(value)
+ value = '#{}#'.format(value)
textnode = True
elif atype == 'real':
value = '{:.18f}'.format(value)
@@ -73,7 +73,8 @@
elif atype == 'color':
value = '#' + value
elif atype == 'font':
- attribs = {'family': unicode(value[0]), 'style': unicode(value[1]), 'name': unicode(value[2])}
+ attribs = {'family': str(value[0]), 'style': str(
+ value[1]), 'name': str(value[2])}
else:
raise ValueError('Unknown type')
@@ -215,14 +216,14 @@
pass
xml = '<?xml version="1.0" encoding="UTF-8"?>' + \
- ET.tostring(dom, encoding='utf-8')
+ ET.tostring(dom, encoding='unicode')
outfile = options['outputfile']
if outfile:
if outfile[-4:] != '.dia':
outfile += '.dia'
with gzip.open(outfile, 'wb') as f:
- f.write(xml)
+ f.write(xml.encode('utf-8'))
else:
print(xml)
@@ -234,12 +235,14 @@
rel['end_obj_id'] = end_rec['id']
idx = None if 'start_field' not in rel or rel['start_field'].primary_key\
- else field_index(start_rec, rel['start_field'])
- rel['start_port'] = allocate_free_port(start_rec) if idx is None else 12 + idx * 2
+ else field_index(start_rec, rel['start_field'])
+ rel['start_port'] = allocate_free_port(
+ start_rec) if idx is None else 12 + idx * 2
idx = None if 'end_field' not in rel or rel['end_field'].primary_key\
- else field_index(end_rec, rel['end_field'])
- rel['end_port'] = allocate_free_port(end_rec) if idx is None else 12 + idx * 2
+ else field_index(end_rec, rel['end_field'])
+ rel['end_port'] = allocate_free_port(
+ end_rec) if idx is None else 12 + idx * 2
def xml_make_table(self, data):
obj = ET.SubElement(self.layer, 'dia:object', attrib={
@@ -258,9 +261,12 @@
make_dia_attribute(obj, 'underline_primary_key', 'boolean', True)
make_dia_attribute(obj, 'bold_primary_keys', 'boolean', False)
- make_dia_attribute(obj, 'normal_font', 'font', ('monospace', 0, 'Courier'))
- make_dia_attribute(obj, 'name_font', 'font', ('sans', 80, 'Helvetica-Bold'))
- make_dia_attribute(obj, 'comment_font', 'font', ('sans', 8, 'Helvetica-Oblique'))
+ make_dia_attribute(
+ obj, 'normal_font', 'font', ('monospace', 0, 'Courier'))
+ make_dia_attribute(
+ obj, 'name_font', 'font', ('sans', 80, 'Helvetica-Bold'))
+ make_dia_attribute(
+ obj, 'comment_font', 'font', ('sans', 8, 'Helvetica-Oblique'))
make_dia_attribute(obj, 'normal_font_height', 'real', 0.8)
make_dia_attribute(obj, 'name_font_height', 'real', 0.7)
make_dia_attribute(obj, 'comment_font_height', 'real', 0.7)
@@ -270,12 +276,14 @@
make_dia_attribute(obj, 'line_colour', 'color', '000000')
make_dia_attribute(obj, 'fill_colour', 'color', data['color'])
- attr = ET.SubElement(obj, 'dia:attribute', attrib={'name': 'attributes'})
+ attr = ET.SubElement(
+ obj, 'dia:attribute', attrib={'name': 'attributes'})
for field in data['fields']:
self.xml_make_field(attr, field)
def xml_make_field(self, parent, data):
- field = ET.SubElement(parent, 'dia:composite', attrib={'type': 'table_attribute'})
+ field = ET.SubElement(
+ parent, 'dia:composite', attrib={'type': 'table_attribute'})
xs = (
('name', 'string'),
@@ -299,23 +307,29 @@
line_style = '4' if data['dotted'] else '0'
if self.bezier:
make_dia_attribute(rel, 'line_style', 'enum', line_style)
- attr = ET.SubElement(rel, 'dia:attribute', attrib={'name': 'corner_types'})
+ attr = ET.SubElement(
+ rel, 'dia:attribute', attrib={'name': 'corner_types'})
ET.SubElement(attr, 'dia:enum', attrib={'val': '0'})
ET.SubElement(attr, 'dia:enum', attrib={'val': '0'})
- attr = ET.SubElement(rel, 'dia:attribute', attrib={'name': 'bez_points'})
+ attr = ET.SubElement(
+ rel, 'dia:attribute', attrib={'name': 'bez_points'})
ET.SubElement(attr, 'dia:point', attrib={'val': '0.0,0.0'})
ET.SubElement(attr, 'dia:point', attrib={'val': '0.0,0.0'})
ET.SubElement(attr, 'dia:point', attrib={'val': '0.0,0.0'})
ET.SubElement(attr, 'dia:point', attrib={'val': '0.0,0.0'})
else:
- attr = ET.SubElement(rel, 'dia:attribute', attrib={'name': 'line_style'})
+ attr = ET.SubElement(
+ rel, 'dia:attribute', attrib={'name': 'line_style'})
ET.SubElement(attr, 'dia:enum', attrib={'val': line_style})
ET.SubElement(attr, 'dia:real', attrib={'val': '1'})
- make_dia_attribute(rel, 'start_point_desc', 'string', data['start_label'])
- make_dia_attribute(rel, 'end_point_desc', 'string', data['end_label'])
+ make_dia_attribute(
+ rel, 'start_point_desc', 'string', data['start_label'])
+ make_dia_attribute(
+ rel, 'end_point_desc', 'string', data['end_label'])
make_dia_attribute(rel, 'corner_radius', 'real', 0)
- make_dia_attribute(rel, 'normal_font', 'font', ('monospace', 0, 'Courier'))
+ make_dia_attribute(
+ rel, 'normal_font', 'font', ('monospace', 0, 'Courier'))
make_dia_attribute(rel, 'normal_font_height', 'real', 0.7)
make_dia_attribute(rel, 'text_colour', 'color', data['color'])
make_dia_attribute(rel, 'orth_autoroute', 'boolean', True)
@@ -324,15 +338,16 @@
ET.SubElement(conns, 'dia:connection', attrib={
'handle': '0',
'to': 'O{}'.format(data['end_obj_id']),
- 'connection': unicode(data['end_port']),
+ 'connection': str(data['end_port']),
})
ET.SubElement(conns, 'dia:connection', attrib={
'handle': '3' if self.bezier else '1',
'to': 'O{}'.format(data['start_obj_id']),
- 'connection': unicode(data['start_port']),
+ 'connection': str(data['start_port']),
})
- make_dia_attribute(rel, 'end_arrow', 'enum', 3 if data['directional'] else 0)
+ make_dia_attribute(
+ rel, 'end_arrow', 'enum', 3 if data['directional'] else 0)
make_dia_attribute(rel, 'end_arrow_length', 'real', 0.25)
make_dia_attribute(rel, 'end_arrow_width', 'real', 0.25)
make_dia_attribute(rel, 'line_colour', 'color', data['color'])
@@ -349,7 +364,7 @@
for app in apps:
result.extend(get_app_models_with_abstracts(app))
result = list(set(result))
- return filter(lambda model: self.get_model_name(model) not in self.exclude_fields, result)
+ return [model for model in result if self.get_model_name(model) not in self.exclude_fields]
def prepare_field(self, field):
return {
@@ -367,7 +382,8 @@
fields = appmodel._meta.local_fields
- # find primary key and print it first, ignoring implicit id if other pk exists
+ # find primary key and print it first, ignoring implicit id if other pk
+ # exists
pk = appmodel._meta.pk
if pk and pk in fields and not appmodel._meta.abstract:
result.append(self.prepare_field(pk))
@@ -380,7 +396,8 @@
result.append(self.prepare_field(field))
if self.sort_fields:
- result = sorted(result, key=lambda field: (not field['primary_key'], field['name']))
+ result = sorted(
+ result, key=lambda field: (not field['primary_key'], field['name']))
return result
@@ -426,9 +443,12 @@
abstract_fields = get_model_abstract_fields(appmodel)
for field in appmodel._meta.local_fields:
- if field.attname.endswith('_ptr_id'): # excluding field redundant with inheritance relation
+ # excluding field redundant with inheritance relation
+ if field.attname.endswith('_ptr_id'):
continue
- if field in abstract_fields: # excluding fields inherited from abstract classes. they too show as local_fields
+ # excluding fields inherited from abstract classes. they too show
+ # as local_fields
+ if field in abstract_fields:
continue
if self.get_field_name(field) in self.exclude_fields:
continue
@@ -442,10 +462,11 @@
continue
if isinstance(field, ManyToManyField):
if (getattr(field, 'creates_table', False) or # django 1.1.
- (hasattr(field.rel.through, '_meta') and field.rel.through._meta.auto_created)): # django 1.2
+ (hasattr(field.rel.through, '_meta') and field.rel.through._meta.auto_created)): # django 1.2
result.append(self.prepare_relation(field, 'n', 'n'))
elif isinstance(field, GenericRelation):
- result.append(self.prepare_relation(field, 'n', 'n', dotted=True))
+ result.append(
+ self.prepare_relation(field, 'n', 'n', dotted=True))
return [rel for rel in result if rel is not None]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.