顧客管理ソフトの作成 – 第3回

今回はデータベースの作成をする。

はじめに

顧客情報を管理するためのテーブルに、顧客CDなどのフィールドを定義していく。作成後にテストデータ作成までを目標に進める。

今回やること

  • sqliteのデータベースを作成
  • 作成したデータベースに顧客テーブルとフィールドを作成
  • テストデータを挿入

sqliteのデータベースを作成

SQLAlchemyのインストール

pythonからデータベースを操作するために、SQLAlchemyをインストールする。

terminal

pip install sqlalchemy

database.pyの作成

データベース作成用のdatabase.pyを作成する。

database.py

"""データベース接続設定"""

import os

from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base, sessionmaker

# DBファイルの保存先をstorage/data フォルダに指定
# プロジェクトルートを基準にする(src の1つ上)
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DB_DIR = os.path.join(PROJECT_ROOT, "storage", "data")
DB_PATH = os.path.join(DB_DIR, "app.db")
DATABASE_URL = f"sqlite:///{DB_PATH}"

# データベースエンジンを作成
engine = create_engine(
    DATABASE_URL,
    # sqlite用の設定
    connect_args={"check_same_thread": False},
)

# テーブルを作成するための基底クラス
Base = declarative_base()


def init_db():
    """データベースファイルを作成する関数"""
    # storage/data フォルダがなければ自動作成
    os.makedirs(DB_DIR, exist_ok=True)
    # DBファイルを作成(既に存在する場合は何もしない)
    Base.metadata.create_all(bind=engine)
    print(f"データベースを作成しました: {DB_PATH}")

main.pyに下記のコード追加。

main.py

from app_layout import AppLayout
from database import init_db # 追加
…
init_db() # 追加
ft.app(main)

実行してstorage\data\app.dbが作成されていれば成功。

modelの作成

顧客テーブルの定義をmodelとして作成する。srcフォルダ直下にmodelsフォルダを作成して、その中にclient.pyを作成する。

修正:2026/3/25

def __repr__(self):関数のインデントがずれていたので修正しました。

client.py

"""顧客テーブルの定義"""

from database import Base
from sqlalchemy import Column, Integer, String, Float, Date, Text, DateTime, func


class Client(Base):
    """顧客情報を保存するテーブル"""

    # テーブル名
    __tablename__ = "clients"

    # 各カラムの定義
    # ID
    id = Column(Integer, primary_key=True, index=True, autoincrement=True)

    # 得意先CD
    client_cd = Column(String(4), nullable=False, unique=True)

    # 得意先名
    client_name = Column(String(50), nullable=False)

    # ふりがな
    client_name_phonetic = Column(String(100), nullable=False)

    # 別名
    client_name_alias = Column(String(50))

    # 郵便番号 ハイフンありの8桁
    postal_code = Column(String(8))

    # 住所
    address = Column(String(30))

    # 電話番号
    phone = Column(String(20))

    # ファックス
    fax = Column(String(20))

    # 代表者
    president = Column(String(20))

    # 与信枠
    credit = Column(Float)

    # 与信枠登録日
    credit_reg_date = Column(Date)

    # 備考
    notes = Column(Text)

    # 登録日
    created_at = Column(
        DateTime, nullable=False, server_default=func.current_timestamp()
    )

    # 更新日
    updated_at = Column(
        DateTime,
        nullable=False,
        server_default=func.current_timestamp(),
        onupdate=func.current_timestamp(),
    )


   def __repr__(self):
       """オブジェクトを文字列で表示するときの形式"""
       # デバッグ時に案件情報を見やすく表示するための機能
       return f"<Client(id={self.id},     client_cd='{self.client_cd}',client_name='{self.client_name}')>"

database.pyのinit_dbに下記のコードを追加して、モデルを登録する。

database.py

def init_db():
…
  os.makedirs(DB_DIR, exist_ok=True)

  from models.client import Client # 追加

  # DBファイルを作成(既に存在する場合は何もしない)
  Base.metadata.create_all(bind=engine)

そして実行して、顧客テーブルが作成されていれば成功。

テストデータ作成

seed.py

"""テストデータの投入"""

from datetime import date

from database import SessionLocal
from models.client import Client


def seed_clients():
    """顧客テーブルにテストデータを投入する関数"""
    db = SessionLocal()

    try:
        # 既にデータがある場合は処理しない
        if db.query(Client).count() > 0:
            print("テストデータは既に存在します。スキップします。")
            return

        # テストデータ
        clients = [
            Client(
                client_cd="0001",
                client_name="山田商事株式会社",
                client_name_phonetic="やまだしょうじ",
                client_name_alias="山田商事 東京",
                postal_code="100-0001",
                address="東京都千代田区千代田1-1-1",
                phone="03-1234-5678",
                fax="03-1234-5679",
                president="山田太郎",
                credit=5000000.0,
                credit_reg_date=date(2024, 4, 1),
                notes="主要取引先",
            ),
            Client(
                client_cd="0002",
                client_name="山田商事株式会社",
                client_name_phonetic="やまだしょうじ",
                client_name_alias="山田商事 大阪",
                postal_code="530-0001",
                address="大阪府大阪市北区梅田2-2-2",
                phone="06-2345-6789",
                fax="06-2345-6780",
                president="鈴木一郎",
                credit=3000000.0,
                credit_reg_date=date(2024, 6, 15),
                notes="",
            ),
            Client(
                client_cd="0003",
                client_name="佐藤電機株式会社",
                client_name_phonetic="さとうでんき",
                client_name_alias="",
                postal_code="460-0001",
                address="愛知県名古屋市中区栄3-3-3",
                phone="052-3456-7890",
                fax="052-3456-7891",
                president="佐藤花子",
                credit=8000000.0,
                credit_reg_date=date(2025, 1, 10),
                notes="新規取引先",
            ),
            Client(
                client_cd="0004",
                client_name="田中物産株式会社",
                client_name_phonetic="たなかぶっさん",
                client_name_alias="",
                postal_code="810-0001",
                address="福岡県福岡市中央区天神4-4-4",
                phone="092-4567-8901",
                fax="092-4567-8902",
                president="田中次郎",
                credit=2000000.0,
                credit_reg_date=date(2024, 9, 1),
                notes="",
            ),
            Client(
                client_cd="0005",
                client_name="高橋建設株式会社",
                client_name_phonetic="たかはしけんせつ",
                client_name_alias="",
                postal_code="980-0001",
                address="宮城県仙台市青葉区中央5-5-5",
                phone="022-5678-9012",
                fax="022-5678-9013",
                president="高橋三郎",
                credit=10000000.0,
                credit_reg_date=date(2024, 1, 1),
                notes="長期取引先。支払い条件:月末締め翌月末払い",
            ),
        ]

        db.add_all(clients)
        db.commit()
        print(f"テストデータを{len(clients)}件投入しました。")

    except Exception as e:
        db.rollback()
        print(f"テストデータの投入に失敗しました: {e}")
    finally:
        db.close()


# terminalから直接実行した場合にテストデータを投入
if __name__ == "__main__":
    from database import init_db

    init_db()
    seed_clients()

データーベースに対して読み書きするために、database.pyにセッション作成するための設定を追加。

database.py

# データベースエンジンを作成
engine = create_engine(
 …

# セッションを作成するための設定
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) # 追加

ここで作成したSessionLocalをseed.pyでインポートして利用している。そして、main.pyにテストデータ作成のコードを追加して実行する。

main.py

init_db()
from seed import seed_clients # 追加

# テストデータ作成
seed_clients() # 追加

ft.app(main)

下記の画像用にテストデータが入っていれば成功。

次回は作成したテストデータを画面に表示する処理を作成する。