一、前言
在第十四天的學習中,我已經使用 Streamlit 建立健康紀錄表單,讓使用者可以輸入日期、喝水量、睡眠時間、運動時間、蔬菜水果攝取情況與備註,並在送出表單後查看輸入結果。
然而,目前的系統仍然存在一個問題:使用者送出的資料還沒有真正保存起來。
如果每次輸入完資料,都只能在畫面上看到結果,之後卻無法再次查詢,就很難持續追蹤個人的健康習慣。因此,今天的目標是將表單與資料保存功能整合,讓使用者每次新增健康紀錄時,系統都能將資料寫入檔案,並在後續使用時重新讀取。
今天將運用先前學習的 Dictionary、Pandas、CSV 與 Streamlit 表單,完成健康習慣追蹤系統的第一個資料新增功能。
二、了解資料新增的流程
在實際撰寫程式之前,需要先整理使用者輸入資料後,系統應該執行哪些步驟。
本次資料新增功能的流程如下:
使用者開啟健康紀錄表單。
填寫日期、喝水量、睡眠時間、運動時間及其他資訊。
點擊送出按鈕。
系統取得表單中的資料。
將資料整理成統一的資料結構。
將資料新增至 CSV 檔案。
顯示新增成功的訊息。
這樣的流程可以讓資料輸入、資料整理與資料保存各自具有明確的工作。
此外,系統也需要考慮第一次使用時尚未建立 CSV 檔案的情況,以及檔案已經存在、需要繼續加入新紀錄的情況。
三、將表單資料整理成 Dictionary
在第九天的學習中,我已經認識 Python 的 List 與 Dictionary,並了解 Dictionary 可以透過鍵值對的方式,將不同欄位與對應資料組合起來。
例如,一筆健康紀錄可以表示為:
health_record = {
"date": "2026-10-26",
"water_ml": 1800,
"sleep_hours": 7.5,
"exercise_minutes": 30,
"vegetables_fruits": True,
"notes": "今天有散步"
}
其中,每個鍵都代表一個資料欄位,而對應的值則是使用者輸入的內容。
這種資料結構有幾個優點:
每個欄位都有明確名稱,方便辨識。
不同型態的資料可以放在同一筆紀錄中。
後續可以直接轉換成 Pandas DataFrame。
可以搭配 CSV 或 SQLite 保存資料。
因此,在新增資料功能中,我會先將表單內容整理成 Dictionary,再交給資料保存的程式處理。
四、使用 Pandas 將資料保存至 CSV
在第十一天的學習中,我已經了解 CSV 可以用來保存表格資料,也學習了如何使用 Pandas 讀取與寫入 CSV 檔案。
今天將運用這個方法,將健康紀錄保存至 health_records.csv。
import pandas as pd
from pathlib import Path
其中,pandas 負責處理表格資料,而 Path 則可以協助檢查檔案是否存在。
import pandas as pd
from pathlib import Path
FILE_PATH = Path("health_records.csv")
def save_health_record(record):
new_record = pd.DataFrame([record])
if FILE_PATH.exists():
old_records = pd.read_csv(FILE_PATH)
all_records = pd.concat(
[old_records, new_record],
ignore_index=True
)
else:
all_records = new_record
all_records.to_csv(
FILE_PATH,
index=False,
encoding="utf-8-sig"
)
這個函式會先將單筆 Dictionary 轉換成 DataFrame,再檢查 CSV 檔案是否已經存在。
如果檔案已存在,程式就會讀取原有紀錄,並使用 pd.concat() 將新資料加入;如果檔案不存在,則直接使用新資料建立檔案。
最後,透過 to_csv() 將完整資料寫入 CSV。
其中,index=False 表示不額外寫入 Pandas 的索引欄位,而 encoding="utf-8-sig" 則有助於讓 CSV 在常見的試算表軟體中正確顯示中文。
需要注意的是,這個基本版本每次新增資料時都會重新寫入整份 CSV,適合目前的小型練習專案。當資料量增加,或需要更完善的資料一致性與查詢功能時,可以再改用 SQLite。
五、整合 Streamlit 表單與資料保存功能
接下來,將第十四天的表單與剛才建立的保存函式整合,讓使用者送出資料時,系統可以直接保存紀錄。
請將 app.py 的內容改成以下程式碼:
import streamlit as st
import pandas as pd
from pathlib import Path
from datetime import date
FILE_PATH = Path("health_records.csv")
def save_health_record(record):
new_record = pd.DataFrame([record])
if FILE_PATH.exists():
old_records = pd.read_csv(FILE_PATH)
all_records = pd.concat(
[old_records, new_record],
ignore_index=True
)
else:
all_records = new_record
all_records.to_csv(
FILE_PATH,
index=False,
encoding="utf-8-sig"
)
st.title("個人健康習慣追蹤系統")
st.write("請填寫今天的健康習慣紀錄。")
with st.form("health_record_form"):
record_date = st.date_input(
"紀錄日期",
value=date.today()
)
water = st.number_input(
"今日喝水量(毫升)",
min_value=0,
max_value=10000,
value=1500,
step=100
)
sleep = st.number_input(
"今日睡眠時間(小時)",
min_value=0.0,
max_value=24.0,
value=8.0,
step=0.5
)
exercise = st.number_input(
"今日運動時間(分鐘)",
min_value=0,
max_value=1440,
value=0,
step=10
)
vegetables_fruits = st.checkbox(
"今天有攝取蔬菜水果"
)
notes = st.text_area(
"今日備註",
placeholder="記錄今天的生活情況"
)
submitted = st.form_submit_button(
"儲存健康紀錄"
)
if submitted:
health_record = {
"date": record_date.isoformat(),
"water_ml": water,
"sleep_hours": sleep,
"exercise_minutes": exercise,
"vegetables_fruits": vegetables_fruits,
"notes": notes.strip()
}
try:
save_health_record(health_record)
st.success("健康紀錄已成功保存!")
st.write("本次新增的資料:")
st.json(health_record)
except (OSError, pd.errors.ParserError) as error:
st.error("資料保存失敗,請檢查檔案狀態與執行權限。")
完成後,在終端機執行:
python -m streamlit run app.py
如果使用 python3,也可以執行:
python3 -m streamlit run app.py
成功啟動後,填寫表單並點擊「儲存健康紀錄」,系統就會將本次輸入的資料保存至 CSV 檔案。
程式中的重要概念

這段程式使用 try...except 處理部分常見的檔案操作錯誤,讓系統在遇到檔案讀寫問題時可以顯示提示,而不是直接呈現完整的錯誤追蹤資訊。
不過,這仍是基本的錯誤處理方式,並未涵蓋所有可能的例外情況。若發生其他未處理的錯誤,仍需要根據終端機訊息進一步除錯。
六、確認資料是否真的保存成功
完成新增功能後,不能只確認畫面是否顯示成功訊息,還需要檢查資料是否真的寫入檔案。
可以使用以下程式讀取 CSV:
import pandas as pd
records = pd.read_csv("health_records.csv")
print(records)
執行後,應該可以看到剛才新增的健康紀錄。
也可以查看檔案所在的資料夾,確認是否已經產生 health_records.csv。
接著,嘗試以下測試:
第一次填寫表單並送出,確認 CSV 檔案是否建立。
再填寫一筆不同日期的紀錄,確認檔案是否包含兩筆資料。
關閉並重新啟動 Streamlit,再讀取 CSV,確認先前的紀錄是否仍然存在。
檢查欄位名稱是否一致,並確認中文備註是否能正常顯示。
如果這些測試都能通過,就代表系統已經具備基本的資料新增與保存能力。
七、今日實作需要注意的地方
目前的版本會將每次送出的資料直接附加至 CSV,因此同一天可以新增多筆紀錄。如果使用者不小心重複送出同一筆資料,檔案中也可能出現重複紀錄。
這是目前版本仍需要改善的地方。未來可以增加日期重複檢查,或讓使用者修改既有紀錄,而不是每次都新增一筆。
此外,今天的程式尚未將第十二天的資料驗證函式完整整合進來。雖然 Streamlit 的數字輸入元件已經限制部分輸入範圍,但正式系統仍應在資料保存前檢查資料是否符合專案規則。
透過這些限制與問題,也能看出系統開發並不是只要讓程式成功執行就好,還需要逐步考慮資料正確性、重複資料與後續維護等需求。
八、今日成果與學習心得
透過今天的學習,我成功將 Streamlit 表單與 CSV 資料保存功能整合,讓健康習慣追蹤系統不再只是接收輸入並顯示結果,而是能夠將資料寫入檔案,並在之後重新讀取。
今天複習了 Dictionary、Pandas DataFrame、CSV 讀寫與檔案存在檢查,也進一步了解如何將資料輸入、資料整理與資料保存分成不同的程式步驟。
目前系統已經可以完成基本的健康紀錄新增流程,但仍需要繼續改善歷史資料查詢、修改與刪除等功能,才能讓整個系統更完整。
九、下一步學習方向
Day 16 將學習「歷史紀錄查詢:查看過去的健康資料」。
接下來會利用 Pandas 讀取已保存的 CSV,並透過 Streamlit 將歷史健康紀錄呈現在網頁中,讓使用者不只能新增資料,也能查看過去的喝水量、睡眠時間、運動時間與其他生活習慣紀錄,逐步建立完整的健康資料管理功能。