11
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

[Django] テーブル定義とER図を出力する View

概要

実装されているモデルのテーブル定義とER図を参照できる view を作成します.

注)テーブル定義は MySQL のみ対応です.

環境

  • Django 2.1
  • MySQL 5.7 (ER図の方は無くても可)

サンプルコード

ここの db_info app にて実装.

ER図の出力には graphviz などが必要になるので Dockerfile も参考になるかもです.

コード

テーブル定義

mysqldump をつかって定義を出力し, それを xsltproc で html に変換したものをレスポンスにします.

参考: https://qiita.com/mamy1326/items/c0aa9252d61ffed31a6e

class TableView(View):
    tmp_dir = None

    # TODO: 出力関連のコードを別モジュールに移動
    def get_target_app_configs(self) -> List[AppConfig]:
        targets = ['users', 'articles']
        return [config for config in apps.app_configs.values() if config.name in targets]

    def get_style_file(self):
        return os.path.join(settings.STATIC_ROOT, 'db_info/style.xsl')

    def get_target_tables(self) -> List[str]:
        """
        app 内のすべてのモデルの table を取得
        """

        configs = self.get_target_app_configs()
        tables = []
        for app_config in configs:
            for model_name, model in app_config.models.items():
                tables.append(model._meta.db_table)
        return tables

    def output_table_info_from_mysql(self) -> str:
        """
        mysqldump を使ってテーブル定義の xml ファイルを出力

        Returns: file name
        """
        db_info = settings.DATABASES['default']
        cmd_params = [
            'mysqldump',
            '--no-data',
            '--xml',
            f'--user={db_info["USER"]}',
            f'--password={db_info["PASSWORD"]}',
            f'--host={db_info["HOST"]}',
            db_info['NAME'],
            '--tables',
        ]
        cmd_params += self.get_target_tables()
        file_name = os.path.join(self.tmp_dir, 'spam.xml')
        with open(file_name, 'wb') as f:
            popen = subprocess.Popen(cmd_params, stdout=f)
        popen.wait()

        return file_name

    def run_convert_xml_to_html(self, xml_path):
        html_path = os.path.join(self.tmp_dir, 'spam.html')
        cmd_params = [
            'xsltproc',
            '--output', html_path,
            self.get_style_file(),
            xml_path
        ]
        subprocess.run(cmd_params)
        return html_path

    def get_table_layout(self):
        xml_path = self.output_table_info_from_mysql()
        return self.run_convert_xml_to_html(xml_path)

    def get(self, request):
        with tempfile.TemporaryDirectory() as d:
            self.tmp_dir = d
            html_file = self.get_table_layout()
            response = HttpResponse(File(open(html_file, 'rb')), content_type='text/html')
            return response

static ファイルを参照するので, お試しする場合は事前に python manage.py collectstatic 必要です.

ER図

django-extensions の graph_models
を使って ER 図を pdf に出力したものをレスポンスにします.

class GraphModelsView(View):

    # TODO: 出力関連のコードを別モジュールに移動
    def get_target_app_names(self) -> List[str]:
        return ['accounts', 'articles']

    def get_options(self):
        return {
            'exclude_models': ['Permission', ],
            'exclude_columns': ['created_at', 'updated_at'],
            'verbose_names': True,
            'group_models': True,
            'disable_sort_fields': True,
        }

    def get(self, request): target_apps = self.get_target_app_names()
        with tempfile.TemporaryDirectory() as d:
            fpath = os.path.join(d, 'spam.pdf')
            kwargs = self.get_options()
            kwargs.update({
                'outputfile': fpath
            })
            call_command('graph_models', *target_apps, **kwargs)

            response = HttpResponse(File(open(fpath, 'rb')), content_type='application/pdf')
            response['Content-Disposition'] = f'inline; filename=er-diagram.pdf'
            return response

補足

  • subprocess をちゃんと理解せず使っているのでおかしなところあるかも.

  • エラー処理をいれていないので, subprocess でエラーになったりするとどうなるかわかんないです><

つかってみる

サンプルコードの Django サーバーを起動し

  • /db_info/table
  • /db_info/graph

にアクセスすると以下の図のように表示されます.

テーブル定義

table.png

論理名欄にはフィールドのコメントが出力されます.
本サンプルでは事前に前回記事 のコマンドを実行しています.
このコマンドはサンプルに今回と同じ db_info app に入れています.

ER 図

er-diagram.png

おわりに

Django モデルのテーブル定義とER図を参照できる View を作成しました.

開発中の最新のモデルの確認・共有ができるのでいいんじゃないでしょうか.

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
11
Help us understand the problem. What are the problem?