Day 85:データモデル設計 ― 「データの“骨格”を整える」
Day 85では、最終プロジェクトの中でもとても重要なテーマ、 データモデル設計 に取り組んでいきます。
今日のキーワードはこの4つです。
- 必要なデータを整理
- テーブル設計
- クラス設計
- ディレクトリ設計
ここを丁寧にやっておくと、 この先の実装がぐっと楽になり、 「迷子にならないプロジェクト」になります。
必要なデータを整理する
「まずは、どんな情報を扱うのかを言葉で書き出す」
最終プロジェクトの例として、 前回の「売上管理・分析システム」を続けて考えてみます。
このシステムで扱いたいデータを、 ざっくり言葉で書き出してみましょう。
- 売上日(いつの売上か)
- 商品名(何を売ったか)
- 金額(いくら売れたか)
- 顧客名(誰に売ったか)
- 支払い方法(現金 / クレジットカードなど)
ここではまだ「テーブル名」や「型」は意識せず、 人間の言葉で書き出すこと が大事です。
ステップ:紙やメモに“項目リスト”を書く
- 「このシステムで管理したい情報」を全部書き出す
- 似たものをグループにまとめる
- 「これは本当に必要?」と自分に問いかける
例えば、こんな感じのメモになります。
- 売上
- 売上日
- 商品名
- 金額
- 顧客名
- 支払い方法
- 顧客
- 顧客名
- メールアドレス
- 電話番号
この時点で、
「売上と顧客は、別の“まとまり”として扱ったほうが良さそうだな」
という感覚が出てきます。
テーブル設計
「データベースの“表”として、情報を整理する」
次に、この情報を テーブル(表) として整理していきます。 ここでは SQLite を使う前提で考えます。
売上テーブルの設計
まずは「売上」を表すテーブルを考えます。
テーブル名:sales
| カラム名 | 型 | 説明 |
|---|---|---|
| id | INTEGER | 主キー(自動採番) |
| date | TEXT | 売上日(YYYY-MM-DD) |
| item | TEXT | 商品名 |
| amount | INTEGER | 売上金額 |
| customer_id | INTEGER | 顧客テーブルへの参照 |
顧客テーブルの設計
テーブル名:customers
| カラム名 | 型 | 説明 |
|---|---|---|
| id | INTEGER | 主キー(自動採番) |
| name | TEXT | 顧客名 |
| TEXT | メールアドレス | |
| phone | TEXT | 電話番号 |
SQLiteのCREATE TABLE例
# repositories/schema.py
import sqlite3
def create_tables() -> None:
"""
sales と customers テーブルを作成します。
すでに存在する場合は何もしません。
"""
conn = sqlite3.connect("sales.db")
cur = conn.cursor()
# 顧客テーブル
cur.execute(
"""
CREATE TABLE IF NOT EXISTS customers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT,
phone TEXT
)
"""
)
# 売上テーブル
cur.execute(
"""
CREATE TABLE IF NOT EXISTS sales (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT NOT NULL,
item TEXT NOT NULL,
amount INTEGER NOT NULL,
customer_id INTEGER,
FOREIGN KEY (customer_id) REFERENCES customers (id)
)
"""
)
conn.commit()
conn.close()
Python重要ポイント:
- 「主キー(id)」を必ず用意する
- 「NOT NULL」で必須項目を明示する
- 「FOREIGN KEY」でテーブル同士の関係を表現する
クラス設計
「Python側でデータの“型”を表現する」
テーブルが決まったら、 次は Python の クラス(モデル) で 同じ情報を表現していきます。
ここでは Pydantic を使ったモデルを例にします。
顧客モデル
# models/customer.py
from pydantic import BaseModel
class Customer(BaseModel):
"""
顧客情報を表すデータモデル。
"""
id: int | None = None # まだDBに保存されていない場合は None
name: str # 顧客名
email: str | None = None # メールアドレス(任意)
phone: str | None = None # 電話番号(任意)
Python売上モデル
# models/sale.py
from pydantic import BaseModel
class Sale(BaseModel):
"""
売上情報を表すデータモデル。
"""
id: int | None = None # まだDBに保存されていない場合は None
date: str # 売上日(文字列で扱う)
item: str # 商品名
amount: int # 売上金額
customer_id: int | None = None # 顧客ID(顧客が未登録の場合は None)
Pythonポイント:
- テーブルのカラムと、クラスの属性を対応させる
idは「まだ保存されていない状態」を表すためにNoneを許容する- 必須項目は型だけを書き、任意項目は
| Noneを付ける
ディレクトリ設計
「どこに何を置くかを決めて、迷子を防ぐ」
Day 82で触れた構成を、 最終プロジェクト用にもう一度整理してみます。
今回の売上管理・分析システムでは、 こんなディレクトリ構成が考えられます。
project/
├── app
│ └── routes.py # FastAPIのルーティング
├── services
│ ├── csv_service.py # CSV処理・データチェック
│ ├── sales_service.py # 売上の登録・集計ロジック
│ └── report_service.py # レポート生成ロジック
├── models
│ ├── customer.py # 顧客モデル
│ └── sale.py # 売上モデル
├── repositories
│ ├── schema.py # テーブル作成
│ ├── customer_repository.py # 顧客のDB操作
│ └── sales_repository.py # 売上のDB操作
├── tests
│ └── test_sales.py # 売上関連のテスト
├── config
│ └── settings.py # 設定(DBパスなど)
└── main.py # アプリのエントリポイント
役割の整理
- app:外からのリクエストを受け取る場所
- services:ビジネスロジック(処理の中心)
- models:データの形(設計図)
- repositories:データベースとのやり取り
- tests:動作確認・品質保証
- config:設定値の管理
- main.py:アプリの起動ポイント
重要ポイント:
「どこに何を書くか」を決めておくと、 コードが増えても、探しやすく・直しやすくなる。
まとめて動かすイメージ
「データモデル設計が、全体の流れを支える」
ここまでの設計を、 ざっくりとした“流れ”としてまとめてみます。
- ユーザーが CSV をアップロードする(
app/routes.py) csv_serviceがデータチェックを行う(services/csv_service.py)- チェック済みデータを
Saleモデルに変換する(models/sale.py) sales_repositoryが SQLite に保存する(repositories/sales_repository.py)sales_serviceが集計処理を行う(services/sales_service.py)report_serviceがレポートを作る(services/report_service.py)- 結果をAPIやExcelとして提供する(
app/routes.py+excel_service)
この一連の流れの“軸”になっているのが、 今日設計した テーブル と クラス(モデル) です。
Day 85ミニテンプレート
「そのまま使えるデータモデル設計セット」
1. テーブル作成スクリプト
# repositories/schema.py
import sqlite3
def create_tables() -> None:
"""
売上管理システムに必要なテーブルを作成します。
"""
conn = sqlite3.connect("sales.db")
cur = conn.cursor()
cur.execute(
"""
CREATE TABLE IF NOT EXISTS customers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT,
phone TEXT
)
"""
)
cur.execute(
"""
CREATE TABLE IF NOT EXISTS sales (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT NOT NULL,
item TEXT NOT NULL,
amount INTEGER NOT NULL,
customer_id INTEGER,
FOREIGN KEY (customer_id) REFERENCES customers (id)
)
"""
)
conn.commit()
conn.close()
Python2. モデルクラス
# models/customer.py
from pydantic import BaseModel
class Customer(BaseModel):
"""
顧客情報を表すデータモデル。
"""
id: int | None = None
name: str
email: str | None = None
phone: str | None = None
Python# models/sale.py
from pydantic import BaseModel
class Sale(BaseModel):
"""
売上情報を表すデータモデル。
"""
id: int | None = None
date: str
item: str
amount: int
customer_id: int | None = None
PythonDay 85のまとめ
「データモデル設計は、プロジェクトの“背骨”をつくる作業」
今日のテーマは、
- 必要なデータを整理
- テーブル設計
- クラス設計
- ディレクトリ設計
でした。
これらを丁寧に考えることで、
「データが迷子にならないプロジェクト」 「変更に強く、育てやすいシステム」
に近づいていきます。
Day 85で“背骨”ができたことで、 この先の実装は、
- どこに何を書くかがはっきりしていて
- データの流れもイメージしやすくて
- テストもしやすい
そんな、気持ちのいい開発になっていきます。
