📁

DJANGO (+DRF) ER図およびテーブル定義の自動作成

2025/01/25に公開

数年ぶりに以前作成したDJANGO DRFのAPIサーバーのデータベース(POSTGRESQL)の資料(データベースの関連がわかる資料)を作成しようと思い、最初はmodels.pyをLLMに読ませてみたところうまくいかず、DUMPのsqlファイルからdot作成してなんて試してもうまくいかずでした。

もともとCRUDなど気にせずFLASKで自由気ままに作っていた野良WEB開発者でしたのでDJANGOを使わなければいけないときは結構苦痛でした。すべてPROJECTの設定ファイルであるsettings.pyの設定であったり、フォルダー構造ががっちりきまっていたりとか、すべて python manage.py xxxx しないといけないみたいな。カスタムSQLをBATCHで動かすのも
[プロジェクトフォルダー]/[アプリフォルダー]/management/commands なんてしなかったり行けなかったり、認証となるとデフォルトで入っている認証とWEBページでなくAPIサーバーとして出すときに非常にとっつきにくい印象はありましたし、面倒だなと思ってました。書籍もほとんどがいわゆるWEBページでDRFはあまりなく、手探りで進めてですが。

ちなみに、以下の書籍は数少ないというか私が知る限りただ1つのDJANGO DRFを日本語で開設した書籍でした。(私は筆者とは面識もメッセージのやり取りも一切なしの無関係な人間です。一応。本当に役に立ったということで引用してます)

現場で使える Django REST Framework の教科書[3.2 LTS 対応版] (Django の教科書シリーズ) [Print Replica] Kindle Edition
by 横瀬 明仁 (Author)

まあ、使っているうちに慣れればこんなもんかと面倒くささがなくなり、開発終盤では逆に、お作法さえ覚えれば、APIのドキュメントを自動作成してSWAGGERで公開などとメリットも多いと感じになりました。(機会があったらこの記事も書きます!)

さて本題でPOSTGRESでできたER図を何とか出せないかと思っていたところ、やっぱりありました!自動で作ってくれる方法!!!

django-extensions + graphviz DJANGOのER図自動作成(Ubuntu 24.04)

方法かいたって簡単でした。

  • django-extensions をインストール
pip install django-extensions
  • graphviz をインストール
apt install graphviz

- 一応図を編集アプリで変更できるようにdotのパッケージもいれます

pip install pydot
  • プロジェクトのsettings.pyに以下をついかです
INSTALLED_APPS = [
    ...
    'django_extensions',
]
  • 図作成
python manage.py graph_models -a -o er_diagram.png

あっけなくかなりプロフェッショナルな見栄えのものできました。

テーブル定義のEXPORT

全体を俯瞰するのであればER図でいいかもしれませんが、やはり個別のテーブルを確認したり、ましてやDJANGOでシステム作って現在のデータを最初に一括でデータインポートが必要になるとどうしてもER図だけでなく詳細なリストが必要です。以下の手順で簡単にできました。プロジェクト内の各models.pyを自動で読んで、テーブル定義にするためのPYTHONスクリプトです。
[table_definition.py]

import csv
from django.apps import apps

output_file = "table_structure.csv"
# すべてのアプリのモデルを取得
models = apps.get_models()

# CSV に保存
with open(output_file, mode="w", newline="", encoding="utf-8") as file:
    writer = csv.writer(file)
    # CSV ヘッダー
    writer.writerow([
        "Table Name", "Table Verbose Name", "Column Name", "Column Verbose Name",
        "Data Type", "Nullable", "Unique", "Default", "Max Length", "Foreign Key To"
    ])
	
    for model in models:
        table_name = model._meta.db_table  # テーブル名
        table_verbose_name = getattr(model._meta, "verbose_name", table_name)  # テーブルの人間向けの名前(未設定ならテーブル名)

        for field in model._meta.fields:
            column_name = field.name  # カラム名
            column_verbose_name = getattr(field, "verbose_name", column_name)  # カラムの人間向けの名前(未設定ならカラム名)

            data_type = field.get_internal_type()  # フィールドの型
            nullable = field.null  # NULL 許可(True or False)
            unique = field.unique  # ユニーク制約(True or False)
            default = field.default if field.default is not None and field.default != field.empty_strings_allowed else "None"
            max_length = field.max_length if hasattr(field, "max_length") else "N/A"  # 最大長(文字列型のみ)

            # 外部キーの関連先テーブルを取得
            foreign_key_to = "N/A"
            if data_type == "ForeignKey":
                foreign_key_to = field.related_model._meta.db_table  # 関連先テーブル名を取得
            
            # CSV に書き込み
            writer.writerow([
                table_name, table_verbose_name, column_name, column_verbose_name,
                data_type, nullable, unique, default, max_length, foreign_key_to
            ])

print(f"テーブル構造を {output_file} に出力しました。")

このスクリプトをDJANGOのルートに設定して以下を実行します。

python manage.py shell

pythonが立ち上がりますので以下で定義がエクスポートされます.
models.pyにしっかりとverboseでカラムの意味を記述しておけばちゃんとして定義書になります。

exec(open("table_definition.py").read())

Discussion