第一階段請參考:
Day24. Flask 與資料庫整合 Ep3:用 TDD(測試驅動開發)完成AI營養顧問的資料庫功能 Part-1
models.py
)# 為了支援 timezone-aware 時間與 JSON 序列化,需加入 `datetime.timezone` 與 `json` 模組
from datetime import datetime, timezone
import json
created_at
# 為了避免時間差的問題,用 datetime.now(timezone.utc) 明確指定要求獲取的是 UTC 時區的當前時間
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
nutrients
屬性(Getter / Setter)此屬性是 nutrients_json
欄位的包裝層,用以自動處理 JSON & Python 結構的轉換。
設計重點:
None
以避免破壞資料庫結構。@property
def nutrients(self):
if not self.nutrients_json:
return []
try:
return json.loads(self.nutrients_json)
except Exception:
return []
@nutrients.setter
def nutrients(self, value):
if isinstance(value, str):
try:
json.loads(value)
self.nutrients_json = value
return
except Exception:
self.nutrients_json = None
return
try:
self.nutrients_json = json.dumps(value, ensure_ascii=False)
except Exception:
self.nutrients_json = None
在測試與實際專案程式中,修正了 SQLAlchemy 的舊 API,這是 SQLAlchemy 2.0 的用法,可避免 LegacyAPIWarning
,目的是確保在未來升級時維持兼容性與穩定性。
# 舊:
# rec = AnalysisRecord.query.get(rid)
# 新:
rec = db.session.get(AnalysisRecord, rid)
pytest -q
測試項目 | 結果 |
---|---|
建立 / 查詢 / 更新 / 刪除 | 全部通過 |
JSON 欄位轉換 | 通過 |
timezone-aware 檢查 | 通過 |
SQLAlchemy 警告 | 無警告 |
pytest 執行結果 | 8 passed in 0.42s |
問題 | 原因與解法 |
---|---|
ImportError: 找不到 models 或 db |
確認於專案根目錄執行 pytest;pytest 會自動將根目錄加入 PYTHONPATH 。 |
IntegrityError: UNIQUE constraint failed |
測試中重複使用相同 image_path 。可於 fixture 中重新建立 in-memory DB,或在每個測試後清空資料表。 |
JSON parsing error |
setter 預設在無法序列化時設為 None 。若要嚴格處理,可改為 raise ValueError 並於測試中檢查例外。 |
Flask-SQLAlchemy
。SQLite
。instance/ainutri.db
。資料庫設定集中於 app.py
的 create_app
:
設定檔:
'sqlite:///ainutri.db'
'sqlite:///:memory:'
(記憶體資料庫,確保測試獨立)初始化:
models.py
中建立全域資料庫:
db = SQLAlchemy()
create_app()
中呼叫 db.init_app(app)
db.create_all()
自動建立資料表。AnalysisRecord
)欄位 | 型別 | 說明 |
---|---|---|
id |
Integer |
主鍵,唯一識別每筆紀錄。 |
image_path |
String(255) |
圖片檔案路徑,unique 以避免重複處理。 |
created_at |
DateTime |
建立時間(使用 UTC)。 |
raw_analysis |
Text |
儲存 AI 回傳的完整文字或 JSON。 |
summary |
Text |
AI 分析的簡短摘要。 |
nutrients_json |
Text |
儲存營養素資訊的 JSON 字串。 |
nutrients
屬性:封裝nutrients_json
反序列化成 Python 結構。專案的資料儲存由使用者自行決定是否要寫入資料庫。
分析與暫存:
上傳圖片後,AI 分析結果會被序列化並暫存在伺服器 session
中。
使用者確認:
使用者在結果頁面檢視分析內容後,再按下「儲存這筆資料」按鈕進行確認。
非同步儲存:
前端以 AJAX 發送 POST 請求至 /save_record
API,
後端從 session
讀取資料,建立 AnalysisRecord
物件:
db.session.add(record)
# 將紀錄正式寫入 SQLite。
db.session.commit()
主題 | 建議 |
---|---|
資料儲存優化 | 改用 PostgreSQL 的 JSONB 型別以支援索引查詢。 |
索引分離架構 | 將向量資料(如 Chroma、FAISS)獨立儲存,僅保留關聯鍵。 |
CI/CD 整合 | 於 GitHub Actions 自動執行 pytest 、flake8 ,確保品質。 |
測試覆蓋率追蹤 | 使用 pytest-cov 監控測試覆蓋率。 |