def test_render_unicode_field_label(self): app_labels = ['django_extensions'] data = generate_graph_data(app_labels, verbose_names=True) models = data['graphs'][0]['models'] model = [x for x in models if x['name'] == 'UnicodeVerboseNameModel'][0] s = model['fields'][1]['label'] self.assertEqual(u'Café', s)
def handle(self, *args, **options): if len(args) < 1 and not options['all_applications']: raise CommandError("need one or more arguments for appname") use_pygraphviz = options.get('pygraphviz', False) use_pydot = options.get('pydot', False) use_json = options.get('json', False) if use_json and (use_pydot or use_pygraphviz): raise CommandError("Cannot specify --json with --pydot or --pygraphviz") cli_options = ' '.join(sys.argv[2:]) graph_data = generate_graph_data(args, cli_options=cli_options, **options) if use_json: self.render_output_json(graph_data, **options) return dotdata = generate_dot(graph_data) if not six.PY3: dotdata = dotdata.encode('utf-8') if options['outputfile']: if not use_pygraphviz and not use_pydot: if HAS_PYGRAPHVIZ: use_pygraphviz = True elif HAS_PYDOT: use_pydot = True if use_pygraphviz: self.render_output_pygraphviz(dotdata, **options) elif use_pydot: self.render_output_pydot(dotdata, **options) else: raise CommandError("Neither pygraphviz nor pydot could be found to generate the image") else: self.print_output(dotdata)
def handle(self, *args, **options): if len(args) < 1 and not options['all_applications']: raise CommandError("need one or more arguments for appname") use_pygraphviz = options.get('pygraphviz', False) use_pydot = options.get('pydot', False) use_json = options.get('json', False) if use_json and (use_pydot or use_pygraphviz): raise CommandError("Cannot specify --json with --pydot or --pygraphviz") cli_options = ' '.join(sys.argv[2:]) graph_data = generate_graph_data(args, cli_options=cli_options, **options) if use_json: self.render_output_json(graph_data, **options) return dotdata = generate_dot(graph_data) if not six.PY3: dotdata = dotdata.encode('utf-8') if options['outputfile']: if not use_pygraphviz and not use_pydot: if HAS_PYGRAPHVIZ: use_pygraphviz = True elif HAS_PYDOT: use_pydot = True if use_pygraphviz: self.render_output_pygraphviz(dotdata, **options) elif use_pydot: self.render_output_pydot(dotdata, **options) else: raise CommandError("Neither pygraphviz nor pydot could be found to generate the image") else: self.print_output(dotdata)
def test_generate_graph_data_can_render_label(self): app_labels = ['auth'] data = generate_graph_data(app_labels) models = data['graphs'][0]['models'] user_data = [x for x in models if x['name'] == 'User'][0] relation_labels = [x['label'] for x in user_data['relations']] self.assertIn("groups (user)", relation_labels)
def test_generate_graph_data_formats_labels_as_bytes(self): app_labels = ['auth'] data = generate_graph_data(app_labels) models = data['graphs'][0]['models'] user_data = [x for x in models if x['name'] == 'User'][0] relation_labels = [x['label'] for x in user_data['relations']] self.assertIn("groups (b'user')", relation_labels)
def test_generate_graph_data_formats_labels_as_bytes(self): app_labels = ['auth'] data = generate_graph_data(app_labels) models = data['graphs'][0]['models'] user_data = [x for x in models if x['name'] == 'User'][0] relation_labels = [x['label'] for x in user_data['relations']] self.assertIn("groups (b'user')", relation_labels)
def test_disabled_on_delete_color_coding(self): app_labels = ['django_extensions'] data = generate_graph_data(app_labels) models = data['graphs'][0]['models'] for model in models: relations = [x for x in model['relations'] if x['type'] in ('ForeignKey', 'OneToOneField')] for relation in relations: self.assertNotIn('color=', relation['arrows'])
def test_render_unicode_field_label(self): app_labels = ['django_extensions'] data = generate_graph_data(app_labels, verbose_names=True) models = data['graphs'][0]['models'] model = [x for x in models if x['name'] == 'UnicodeVerboseNameModel'][0] fields = dict((_f['name'], _f['label']) for _f in model['fields']) expected = { 'id': u'ID', 'cafe': u'Café', 'parent_cafe': u'Café latte', } self.assertEqual(expected, fields)
def test_on_delete_color_coding(self): app_labels = ['django_extensions'] data = generate_graph_data(app_labels, color_code_deletions=True) models = data['graphs'][0]['models'] for model in models: relations = [x for x in model['relations'] if x['type'] in ('ForeignKey', 'OneToOneField')] for relation in relations: field = [x['field'] for x in model['fields'] if x['name'] == relation['name']][0] on_delete = getattr(field.remote_field, 'on_delete', None) expected_color = ON_DELETE_COLORS[on_delete] self.assertIn('color={}'.format(expected_color), relation['arrows'])
def test_no_models_dot_py(self): data = generate_graph_data(['testapp_with_no_models_file']) self.assertEqual(len(data['graphs']), 1) model_name = data['graphs'][0]['models'][0]['name'] self.assertEqual(model_name, 'TeslaCar')
def test_no_models_dot_py(self): data = generate_graph_data(['testapp_with_no_models_file']) self.assertEqual(len(data['graphs']), 1) model_name = data['graphs'][0]['models'][0]['name'] self.assertEqual(model_name, 'TeslaCar')
def build_html( # noqa: C901 app_labels: list = APP_LABELS, html_top: str = HTML_TOP, html_bottom: str = HTML_BOTTOM, ) -> str: """Create an HTML page with a series of html tables for each table in the database. Args: app_labels (list): List of Django apps to include in HTML page. Defaults to APP_LABELS. html_top (str): HTML code to insert above generated table. Defaults to HTML_TOP. html_bottom (str): HTML code to insert below generated table. Defaults to HTML_BOTTOM. Returns: str: HTML page. """ # generate a dict with the table names as keys output_table_dict = {} for label in app_labels: # read basic data with django_extensions.management.modelviz data = generate_graph_data([label]) for db_table in data["graphs"][0]["models"]: # generate data for each table (include help_text if present, if not use verbose_name) table_fields = [] for field in db_table["fields"]: if field["help_text"]: description = field["help_text"] else: description = field["verbose_name"] data_type = f'<code>{field["db_type"]}</code>' if field["relation"]: field_type = field["internal_type"] field_type = field_type.replace("ForeignKey", "FK") data_type = f"{data_type} (<b>{field_type}</b>)" # elif field["type"] == "AutoField": # data_type = f'{data_type}<br/><b>{field["type"]}</b>' nullable = "✅" if field["null"] else "❌" unique = "✅" if field["unique"] else "❌" table_fields.append([ f"<code>{field['column_name']}</code>", data_type, unique, nullable, description, ]) # only include tables that are stored in db if (db_table["fields"][0]["name"] == "id" and db_table["fields"][0]["type"] == "AutoField"): # create table info text from docstring docstring_html = db_table["docstring"].replace( "\n\n", "<br />\n") info_text = f"<p>{docstring_html}</p>" # if table uses foreign keys: create a list of foreign keys with links if db_table["relations"]: relation_text = "" for relation in db_table["relations"]: if relation["type"] == "ForeignKey": relation_text += f'<li><a href="#{relation["target"]}"><code>{relation["target_table_name"]}</code></a> via <code>{relation["column_name"]}</code></li>' # elif relation["type"] == "ManyToManyField": # relation_text += f'<li><code>{relation["column_name"]}</code> aus der Tabelle <a href="#{relation["target"]}">{relation["target_table_name"]}</a> (ManyToMany)</li>' if relation_text: if db_table["is_m2m_table"]: info_text += "<p>Sie verbindet die folgenden Tabellen:</p>" else: info_text += "<p>Diese Tabelle hat folgende Relationen zu anderen Tabellen:</p>" info_text += "<ul>" info_text += relation_text info_text += "</ul>" if db_table["unique_together"]: info_text += "Für die Tabelle sind die folgenden <code>UNIQUE</code> Constraints definiert: <ul>" for tup in db_table["unique_together"]: info_text += f"<li>{', '.join(f'<code>{field}</code>' for field in tup)}</li>" info_text += "</ul>" # combine table name, table info text, table fields, and Django model name output_table_dict[db_table["db_table_name"]] = [ info_text, table_fields, db_table["name"], ] # sort dict of database tables alphabetically output_sorted = collections.OrderedDict(sorted(output_table_dict.items())) # collect HTML items in a string html_tables = "" for table_name, table_infos in output_sorted.items(): # convert output table to HTML html_tables += f"<a name='{table_infos[2]}'></a>" # For backwards compatibility html_tables += ( f"<h3><a name='{table_name}' href='#{table_name}'>{table_name}</a></h3>" + f"<div class='docstring'>{table_infos[0]}</div>" + "\n" + tabulate( ["Name", "Type", "UNIQUE", "NULL", "Beschreibung"], table_infos[1], head_classes={ 2: "mono", 3: "mono" }, row_classes={ 2: "hcenter vcenter", 3: "hcenter vcenter" }, ) + "\n") return str(html_top + html_tables + html_bottom)