1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python-Flaskで作る!テーブル定義書とCREATE文を画面入力から自動生成するWebツール(プログラム付き)

Posted at

はじめに

データベース設計時、テーブル定義書を作成しながらCREATE文を同時に生成できるツールがあったら便利だと思いませんか?本記事では、Pythonの軽量なWebフレームワーク「Flask」を使い、テーブル定義書とCREATE文を自動生成するWebツールを作る方法を解説します。

完成イメージ:

  1. ユーザーがWebフォームにテーブル名とカラム情報を入力
  2. 「生成」ボタンをクリック
  3. 結果画面に以下を表示:
    • テーブル定義書(カラム情報を表形式で表示)
    • CREATE文

完成イメージ

スクリーンショット 2024-12-24 18.48.24.png
スクリーンショット 2024-12-24 18.48.30.png

構成と準備

必要なツール

  • Python(バージョン3.7以上)
  • Flask(軽量Webフレームワーク)
  • pandas(テーブルデータを扱うためのライブラリ)

以下のコマンドで必要なライブラリをインストールします。

pip install flask pandas

ディレクトリ構成

作成するディレクトリ構成は以下の通りです:

table_generator/
├── app.py                   # Flaskアプリケーションのメインコード
├── requirements.txt         # 必要なライブラリのリスト
├── templates/               # HTMLテンプレートを格納
│   ├── index.html           # 入力フォームページ
│   └── result.html          # 結果表示ページ
├── static/                  # 静的ファイルを格納
│   ├── css/                 # CSSファイルを格納
│   │   └── styles.css       # スタイルシート
│   └── js/                  # JavaScriptファイルを格納
│       └── scripts.js       # 行追加用スクリプト

コード詳細

1. Flaskアプリケーション: app.py

app.pyは、Flaskアプリケーションの中心となるコードです。ユーザーの入力データを受け取り、CREATE文とテーブル定義書を生成します。

from flask import Flask, render_template, request
import pandas as pd

app = Flask(__name__)

@app.route('/')
def index():
    """入力フォームページを表示"""
    return render_template('index.html')

@app.route('/generate', methods=['POST'])
def generate():
    """フォームデータからCREATE文とテーブル定義書を生成して結果ページを表示"""
    try:
        # フォームデータを取得
        table_name = request.form.get('table_name', '').strip()  # テーブル名
        columns = request.form.getlist('columns[]')  # カラム名リスト
        data_types = request.form.getlist('data_types[]')  # データ型リスト
        lengths = request.form.getlist('lengths[]')  # 長さリスト
        not_nulls = request.form.getlist('not_nulls[]')  # NOT NULL制約リスト
        defaults = request.form.getlist('defaults[]')  # デフォルト値リスト
        primary_keys = request.form.getlist('primary_keys[]')  # 主キーリスト

        # 入力データのバリデーション
        if not table_name:
            return "テーブル名を入力してください。", 400
        if not columns or not any(columns):
            return "少なくとも1つのカラム情報を入力してください。", 400

        # データ整合性を補正
        max_length = max(len(columns), len(data_types), len(lengths), len(not_nulls), len(defaults), len(primary_keys))

        def pad_list(lst, length):
            return lst + [''] * (length - len(lst))

        # 配列を補正して長さを揃える
        columns = pad_list(columns, max_length)
        data_types = pad_list(data_types, max_length)
        lengths = pad_list(lengths, max_length)
        not_nulls = pad_list(not_nulls, max_length)
        defaults = pad_list(defaults, max_length)
        primary_keys = pad_list(primary_keys, max_length)

        # CREATE文を生成
        create_sql = f"CREATE TABLE {table_name} (\n"
        primary_keys_list = []

        for i in range(max_length):
            if not columns[i]:
                continue
            line = f"  {columns[i]} {data_types[i]}"
            if lengths[i]:
                line += f"({lengths[i]})"
            if not_nulls[i] == 'Yes':
                line += " NOT NULL"
            if defaults[i]:
                line += f" DEFAULT {defaults[i]}"
            if primary_keys[i] == 'Yes':
                primary_keys_list.append(columns[i])
            line += ",\n"
            create_sql += line

        # 主キー定義を追加
        if primary_keys_list:
            create_sql += f"  PRIMARY KEY ({', '.join(primary_keys_list)}),\n"

        create_sql = create_sql.rstrip(',\n') + "\n);"

        # テーブル定義データを作成
        table_definition = [
            {
                "column": columns[i],
                "data_type": data_types[i],
                "length": lengths[i],
                "not_null": "Yes" if not_nulls[i] == "Yes" else "No",
                "default": defaults[i],
                "primary_key": "Yes" if primary_keys[i] == "Yes" else "No",
            }
            for i in range(max_length)
            if columns[i]
        ]

        return render_template('result.html', create_sql=create_sql, table_definition=table_definition)

    except Exception as e:
        return f"エラーが発生しました: {e}", 500

if __name__ == '__main__':
    app.run(debug=True)

2. フォーム入力ページ: templates/index.html

フォームにテーブル情報を入力できるページです。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>テーブル定義作成ツール</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
</head>
<body>
    <h1>テーブル定義作成ツール</h1>
    <form action="/generate" method="POST">
        <label>テーブル名:</label>
        <input type="text" name="table_name" required>

        <table id="columns-table">
            <tr>
                <th>カラム名</th>
                <th>データ型</th>
                <th>長さ</th>
                <th>NOT NULL</th>
                <th>デフォルト値</th>
                <th>主キー</th>
            </tr>
            <tr>
                <td><input type="text" name="columns[]" required></td>
                <td><input type="text" name="data_types[]" required></td>
                <td><input type="text" name="lengths[]"></td>
                <td><input type="checkbox" name="not_nulls[]" value="Yes"></td>
                <td><input type="text" name="defaults[]"></td>
                <td><input type="checkbox" name="primary_keys[]" value="Yes"></td>
            </tr>
        </table>
        <button type="button" onclick="addRow()">行を追加</button>
        <button type="submit">生成</button>
    </form>
    <script src="{{ url_for('static', filename='js/scripts.js') }}"></script>
</body>
</html>

3. 結果表示ページ: templates/result.html

生成されたCREATE文とテーブル定義書を表示します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>生成結果</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
</head>
<body>
    <h1>生成結果</h1>
    <form action="/">
        <button type="submit">戻る</button>
    </form>
    <h2>CREATE文</h2>
    <pre>{{ create_sql }}</pre>
    <h2>テーブル定義書</h2>
    <table>
        <tr>
            <th>カラム名</th>
            <th>データ型</th>
            <th>長さ</th>
            <th>NOT NULL</th>
            <th>デフォルト値</th>
            <th>主キー</th>
        </tr>
        {% for row in table_definition %}
        <tr>
            <td>{{ row.column }}</td>
            <td>{{ row.data_type }}</td>
            <td>{{ row.length }}</td>
            <td>{{ row.not_null }}</td>
            <td>{{ row.default }}</td>
            <td>{{ row.primary_key }}</td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

4. スタイル: static/css/styles.css

見た目を整えるためのCSSです。

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
    background-color: #f9f9f9;
}

h1 {
    text-align: center;
    margin: 20px 0;
}

.form-container {
    max-width: 800px;
    margin: 20px auto;
    padding: 20px;
    background: #ffffff;
    border-radius: 5px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

label {
    display: block;
    margin-bottom: 10px;
    font-weight: bold;
}

input[type="text"] {
    width: calc(100% - 10px);
    padding: 8px;
    margin-bottom: 10px;
    border: 1px solid #ccc;
    border-radius: 3px;
    box-sizing: border-box;
}

table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 10px;
}

th, td {
    padding: 10px;
    text-align: left;
    border: 1px solid #ddd;
}

button {
    background-color: #4CAF50;
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 3px;
    cursor: pointer;
    font-size: 16px;
}

button:hover {
    background-color: #45a049;
}

.add-row {
    margin-top: 10px;
    background-color: #2196F3;
}

.add-row:hover {
    background-color: #1976D2;
}

.submit-btn {
    display: block;
    width: 100%;
    margin-top: 20px;
}

.result-container {
    max-width: 800px;
    margin: 20px auto;
    background: #ffffff;
    padding: 20px;
    border-radius: 5px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.sql-preview {
    background: #f8f8f8;
    padding: 10px;
    border-radius: 5px;
    font-family: monospace;
    overflow-x: auto;
}

.back-btn {
    background-color: #f44336;
}

.back-btn:hover {
    background-color: #d32f2f;
}


5. 動的行追加スクリプト: static/js/scripts.js

function addRow() {
    const table = document.getElementById('columns-table');
    const newRow = table.insertRow();
    ['columns[]', 'data_types[]', 'lengths[]', 'not_nulls[]', 'defaults[]', 'primary_keys[]'].forEach((name) => {
        const cell = newRow.insertCell();
        if (name.includes('not_nulls') || name.includes('primary_keys')) {
            cell.innerHTML = `<input type="checkbox" name="${name}" value="Yes">`;
        } else {
            cell.innerHTML = `<input type="text" name="${name}" required>`;
        }
    });
}

実行方法

  1. サーバーを起動します。

    python app.py
    
  2. ブラウザで http://localhost:5000 にアクセス。


まとめ

この記事では、Flaskを使った簡単なWebツールの作成方法を解説しました。このツールをカスタマイズして、より複雑なデータベーススキーマ設計にも応用できます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?