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)
Beispiel #4
0
    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)
Beispiel #6
0
    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')
Beispiel #12
0
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)