Day 86:基本機能を実装 ― 「まずは“動く一本の線”を通す」
Day 86では、いよいよ最終プロジェクトの 基本機能を実装 していきます。
テーマはとてもシンプルで、でも本質的です。
入力 ↓ データ処理 ↓ 保存
この「一本の流れ」を、まずは確実に通します。 細かい機能や見た目は、あとからいくらでも育てられます。 最初にやるべきことは、
「データがちゃんと入って、処理されて、保存される」
この“動く一本の線”を作ることです。
ここでは、前回までの「売上管理・分析システム」を例に、 CSV → データチェック → SQLite保存 という流れを、ステップバイステップで組み立てていきます。
全体の流れをもう一度イメージする
まずは、今日作る「一本の線」を、言葉で整理してみます。
- ユーザーが売上CSVをシステムに渡す(入力)
- システムがCSVを読み込み、データをチェックする(データ処理)
- チェック済みデータをSQLiteに保存する(保存)
この3ステップが完成すると、
- 「とりあえずデータは入る」
- 「壊れたデータは弾かれる」
- 「あとから集計やレポートが作れる」
という状態になります。
では、ひとつずつコードにしていきましょう。
入力 ― 「まずはCSVを受け取れるようにする」
シンプルなスタート:ファイルパスを受け取る関数
最初からWeb APIにしてもいいのですが、 ここでは 「まずはシンプルに、ローカルのCSVファイルを読む」 ところから始めます。
# services/csv_input.py
import csv
from typing import Any
def read_csv(path: str) -> list[dict[str, Any]]:
"""
CSVファイルを読み込み、1行ごとに辞書として返します。
path: 読み込みたいCSVファイルのパス
戻り値: 各行を辞書にしたリスト
"""
rows: list[dict[str, Any]] = []
# ファイルを開く
with open(path, encoding="utf-8") as f:
reader = csv.DictReader(f)
# 1行ずつ読み込んでリストに追加
for row in reader:
rows.append(row)
return rows
Pythonここでやっていることは、とても素直です。
csv.DictReaderを使って、ヘッダー行をキーにした辞書として読む- 各行を
rowsリストに追加していく - 最終的に「行のリスト」を返す
ポイント:
「まずは、データが“入ってくる”ところを作る」 ここではまだ、チェックも保存もしていません。 入力だけに集中します。
データ処理 ― 「壊れていないかを確認し、型を整える」
次に、読み込んだデータを 処理(チェック+整形) します。
売上データのバリデーションと整形
# services/sales_processing.py
from typing import Any
from models.sale import Sale
def validate_and_convert(rows: list[dict[str, Any]]) -> list[Sale]:
"""
CSVから読み込んだ行データをチェックし、
Saleモデルのリストに変換します。
- 必須項目が空でないか
- 金額が整数として扱えるか
などを確認します。
"""
sales: list[Sale] = []
for row in rows:
# 必須項目チェック
if not row.get("date"):
raise ValueError("date が空です")
if not row.get("item"):
raise ValueError("item が空です")
if not row.get("amount"):
raise ValueError("amount が空です")
# 金額を整数に変換
try:
amount_int = int(row["amount"])
except ValueError:
raise ValueError(f"amount が整数ではありません: {row['amount']}")
# Saleモデルに変換
sale = Sale(
id=None, # まだDBに保存していないので None
date=row["date"],
item=row["item"],
amount=amount_int,
customer_id=None, # 今回は顧客情報なしでスタート
)
sales.append(sale)
return sales
Pythonここでの大事なポイントは3つです。
- 必須項目のチェック
date/item/amountが空ならエラー
- 型の整形
amountをintに変換しておく
- モデルへの変換
- 生の辞書ではなく、
Saleクラスにしておく
- 生の辞書ではなく、
「生のデータを、そのままシステムに流さない」 これが、セキュリティと品質の両方の面で、とても大事な考え方です。
保存 ― 「チェック済みデータをSQLiteに蓄える」
最後に、整形済みの Sale を SQLiteに保存 します。
売上保存用のリポジトリ
# repositories/sales_repository.py
import sqlite3
from models.sale import Sale
DB_PATH = "sales.db"
def save_sales(sales: list[Sale]) -> None:
"""
SaleモデルのリストをSQLiteに保存します。
"""
conn = sqlite3.connect(DB_PATH)
cur = conn.cursor()
for sale in sales:
cur.execute(
"""
INSERT INTO sales (date, item, amount, customer_id)
VALUES (?, ?, ?, ?)
""",
(sale.date, sale.item, sale.amount, sale.customer_id),
)
conn.commit()
conn.close()
Pythonポイント:
- リポジトリ層は「DBとの会話だけ」に集中する
Saleモデルを受け取り、カラムに対応させてINSERTする- コミットとクローズを忘れない
3つをつなぐ「メインの一本の線」を作る
ここまでで、
- 入力:
read_csv - データ処理:
validate_and_convert - 保存:
save_sales
という3つの部品ができました。
これを ひとつの流れ としてつなぐのが、 Day 86のクライマックスです。
# main.py
from services.csv_input import read_csv
from services.sales_processing import validate_and_convert
from repositories.sales_repository import save_sales
from repositories.schema import create_tables # テーブル作成用
def main() -> None:
"""
基本機能のメイン処理。
入力 → データ処理 → 保存 の一本の線を通します。
"""
# 1. テーブルがなければ作成
create_tables()
# 2. CSVを読み込む(入力)
rows = read_csv("sales_sample.csv")
print(f"読み込んだ行数: {len(rows)}")
# 3. データチェック&整形(データ処理)
sales = validate_and_convert(rows)
print(f"有効な売上データ件数: {len(sales)}")
# 4. SQLiteに保存(保存)
save_sales(sales)
print("売上データを保存しました")
if __name__ == "__main__":
main()
Pythonこの main() が、 今日のテーマである 「最重要機能の一本の線」 です。
重要な“設計の感覚”をもう一度整理する
Day 86で、みなさんが掴んでほしい感覚は、 単に「コードが動いた」ということだけではありません。
それ以上に大事なのは、次の3つです。
1. 入力・処理・保存を分ける
- 入力:ファイルやAPIからデータを受け取る
- 処理:チェック・整形・変換を行う
- 保存:データベースに蓄える
この3つを 別々の関数・モジュール に分けることで、
- 変更しやすくなる
- テストしやすくなる
- バグの原因を特定しやすくなる
というメリットが生まれます。
2. 生データをそのまま信じない
CSVや外部入力は、 必ずしも「きれいなデータ」とは限りません。
- 空欄
- 型違い
- 想定外の値
こうしたものを、 処理の前にちゃんとチェックする ことで、
「システムの中に“汚れ”を持ち込まない」
という状態を作れます。
3. モデル(クラス)を通して扱う
辞書や生の行データではなく、 Sale のような モデルクラス を通して扱うことで、
- 型ヒントが効く
- 意図がコードに残る
- ツール(mypyなど)がチェックしてくれる
という、コード品質の面でのメリットも得られます。
Day 86ミニテンプレート ― そのまま使える「基本機能セット」
最後に、今日の内容を ひとまとめのテンプレートとして並べておきます。
1. 入力
# services/csv_input.py
import csv
from typing import Any
def read_csv(path: str) -> list[dict[str, Any]]:
"""
CSVファイルを読み込み、1行ごとに辞書として返します。
"""
rows: list[dict[str, Any]] = []
with open(path, encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
rows.append(row)
return rows
Python2. データ処理
# services/sales_processing.py
from typing import Any
from models.sale import Sale
def validate_and_convert(rows: list[dict[str, Any]]) -> list[Sale]:
"""
CSVから読み込んだ行データをチェックし、
Saleモデルのリストに変換します。
"""
sales: list[Sale] = []
for row in rows:
if not row.get("date"):
raise ValueError("date が空です")
if not row.get("item"):
raise ValueError("item が空です")
if not row.get("amount"):
raise ValueError("amount が空です")
try:
amount_int = int(row["amount"])
except ValueError:
raise ValueError(f"amount が整数ではありません: {row['amount']}")
sale = Sale(
id=None,
date=row["date"],
item=row["item"],
amount=amount_int,
customer_id=None,
)
sales.append(sale)
return sales
Python3. 保存
# repositories/sales_repository.py
import sqlite3
from models.sale import Sale
DB_PATH = "sales.db"
def save_sales(sales: list[Sale]) -> None:
"""
SaleモデルのリストをSQLiteに保存します。
"""
conn = sqlite3.connect(DB_PATH)
cur = conn.cursor()
for sale in sales:
cur.execute(
"""
INSERT INTO sales (date, item, amount, customer_id)
VALUES (?, ?, ?, ?)
""",
(sale.date, sale.item, sale.amount, sale.customer_id),
)
conn.commit()
conn.close()
Python4. 一本の線を通すメイン
# main.py
from services.csv_input import read_csv
from services.sales_processing import validate_and_convert
from repositories.sales_repository import save_sales
from repositories.schema import create_tables
def main() -> None:
"""
入力 → データ処理 → 保存 の基本機能を実行します。
"""
create_tables()
rows = read_csv("sales_sample.csv")
sales = validate_and_convert(rows)
save_sales(sales)
print("基本機能が正常に動作しました")
if __name__ == "__main__":
main()
PythonDay 86のまとめ ― 「まずは一本の線を通す。それが“作品”の始まり」
今日のテーマは、
- 入力
- データ処理
- 保存
という、システムの 最重要な3ステップ を 実際のコードとして形にすることでした。
この一本の線が通った瞬間、 プロジェクトは「設計図」から、 「動く作品」 に変わります。
Day 86を終えた今、 みなさんのプロジェクトには、 すでに「心臓の鼓動」のようなものが宿っています。
ここから先は、
- 集計機能
- API提供
- レポート出力
- テスト
などを少しずつ足していきながら、 作品としての完成度を高めていく時間です。
でも、そのすべての土台になっているのは、 今日作った 「入力 → 処理 → 保存」 の一本の線。
それを、誇っていい一歩として、 静かに、でも確かに、胸に置いておいてください。
