I took a completely different approach. You can see the relationship in the code view. ‘I’ wrote a Python programme that uses AST to convert Python code into Mermaid output, which can then be imported into draw.io. It’s not the coolest solution, but it works.
I just did a short demo
Here you see the table with 2 References
Thats how it looks after the script, importing the mermind “code”
That is the Python Script (testet with 3.13.7)
You just need to replace the code in the string python_code
import ast
class ERDGenerator(ast.NodeVisitor):
def __init__(self):
self.classes = {}
self.relationships = []
def visit_ClassDef(self, node):
class_name = node.name
attributes = []
for item in node.body:
if isinstance(item, ast.Assign):
for target in item.targets:
if isinstance(target, ast.Name):
attr_name = target.id
attr_type = self.get_attribute_type(item.value)
attributes.append((attr_type, attr_name)) # Store as tuple (type, name)
elif isinstance(item, ast.FunctionDef):
# Skip methods for ERD
continue
self.classes[class_name] = attributes
self.generic_visit(node)
def get_attribute_type(self, value):
if isinstance(value, ast.Call):
if isinstance(value.func, ast.Attribute):
# Handle cases like grist.Text() or grist.Reference()
if value.func.attr == 'Text':
return 'string'
elif value.func.attr == 'Reference':
if isinstance(value.args[0], ast.Constant):
return value.args[0].value # Return the name in the brackets
elif value.func.attr == 'Numeric':
return 'float'
elif value.func.attr == 'Any':
return 'string'
elif value.func.attr == 'DateTime':
return 'DateTime'
elif value.func.attr == 'Integer':
return 'Integer'
elif value.func.attr == 'Toggle':
return 'Boolean'
elif value.func.attr == 'Date':
return 'Date'
elif value.func.attr in ['Choice', 'Choice List']:
return 'List'
return "unknown"
def generate_mermaid(self):
mermaid_diagram = "erDiagram\n\n"
for class_name, attributes in self.classes.items():
mermaid_diagram += f" {class_name} {{\n"
for attr_type, attr_name in attributes:
mermaid_diagram += f" {attr_type} {attr_name}\n"
mermaid_diagram += " }\n\n"
# Create relationships based on foreign keys
for class_name, attributes in self.classes.items():
for attr_type, attr_name in attributes:
if attr_type in self.classes: # Check if the attribute type is a class name
mermaid_diagram += f" {class_name} ||--|| {attr_type}: has\n"
return mermaid_diagram
def convert_python_to_mermaid(python_code):
tree = ast.parse(python_code)
erd_generator = ERDGenerator()
erd_generator.visit(tree)
return erd_generator.generate_mermaid()
# Example Python code input
python_code = '''
@grist.UserTable
class Items:
Nr = grist.Date()
Name = grist.Text()
@grist.UserTable
class Kunde:
A = grist.Text()
def B(rec, table):
return None
def C(rec, table):
return None
@grist.UserTable
class Order:
Kunde = grist.Reference('Kunde')
Date = grist.Date()
Items = grist.Reference('Items')
def A(rec, table):
return None
'''
# Convert and print the Mermaid ERD
mermaid_output = convert_python_to_mermaid(python_code)
with open ("mermaid_output.txt","w",encoding="utf-8") as file:
file.write(mermaid_output)
The Mermind-Code looks like
erDiagram
Items {
Date Nr
string Name
}
Kunde {
string A
}
Order {
Kunde Kunde
Date Date
Items Items
}
Order ||--|| Kunde: has
Order ||--|| Items: has
I know this topic is quite old, but perhaps it will help as a workaround.
Greets
Philip