🚀 Day 10:整合優化與專案發布展演(Integration, Deployment & Demo Day)

5 天營隊第二週大結局 (Day 10 / 總時數 6 Hours) | 視覺化數據圓餅圖、雲端 Server 部署上線與專屬網址發布會!

📖 為什麼學 these?——「理財咖啡館完工開幕!衝向雲端伺服器」關卡冒險故事線

💡 故事情境:將本機專案部署到網際網路,拿下一串屬於你自己的專屬網址!

過去 9 天我們從終端機控制台開始,一路建立了資料庫與動態互動網頁。今天是我們的 **畢業大登頂時刻**!我們要加入 **Chart.js 圓餅圖** 進行數據視覺化,打包相依套件並鎖上安全開關,最後將專案上傳到雲端主機平台,拿到專屬網址(如 xxx.pythonanywhere.com),立馬傳給班級群組與父母看你的心血結晶!

單元名稱 記帳程式關卡角色 為什麼這個單元不可或缺?(技術關聯)
單元 1:前端進階:資料視覺化 📊 理財數據圓餅圖 (Chart.js) 將 Django View 算出的分類統計數字丟給前端 JavaScript,自動渲染成漂亮的炫酷圓餅圖與柱狀圖!
單元 2:上線前置準備 🧳 打包行李箱與安全鎖 (.env & DEBUG) 匯出 requirements.txt 套件清單,將 DEBUG = False 關閉除錯保護商業機密,設定 ALLOWED_HOSTS
單元 3:雲端部署平台介紹 ☁️ 租用 24hr 不打烊雲端主機 (PaaS) 認識 PythonAnywhere / Render 雲端平台,擺脫 127.0.0.1 本地端限制,邁向網際網路全世界。
單元 4:實戰部署 (Deployment) 🚚 專案搬家上雲與 Cloud Migrate 將程式碼上傳至雲端主機,在雲端伺服器執行 python manage.py migrate 建立正式資料庫。
單元 5:靜態檔案與除錯 🎨 雲端外觀收集與極限除錯 (collectstatic) 執行 collectstatic 解決雲端 CSS/JS 遺失問題,進行上線前最後的 Live 除錯與壓力測試。
單元 6:🎓 Demo Day 成果發表會 🏆 理財全棧工程師雲端發布會 秀出專屬網址、現場操作網頁記帳,進行全班作品互評與體驗,頒發 30 小時 Python 全棧營隊結業證書!

📌 課程前導與簡介說明

🎓 教師心法與教學策略 (Teacher Only)
  • 營隊定位:衝刺部署上線與成果展演。這是 30 小時密集營隊的巔峰與高潮。
  • 高中生心理亮點:當學生拿到真正的公網 URL(如 xxx.pythonanywhere.com),用手機打開並真的可以在上面記帳時,這種成就感會深植人心一輩子!
  • 教學銜接點:強調真實軟體發布上線 (Deployment) 流程;靜態檔案 `collectstatic` 與 `DEBUG = False` 是 Deploy 時最常卡關之處,需細心引導。
🌟 學生自主學習指引 (Student Self-Study)

歡迎來到最後一天大結局!今天你要把網站真正部署到雲端網際網路上!請閱讀每個單元的 **故事單元說明**,點擊 **延伸閱讀** 展開深層觀念與 Google 搜尋,遇到部署除錯問題時善用 **AI 協作除錯提示詞**!

💻 Day 10 專案總成果:Chart.js 圖表整合與雲端部署設定

【教師參考解答】學生於 Day 10 結束時將完成的圖表 View、HTML Canvas 與部署設定:

1. 圖表 View 資料準備 (`expenses/views.py`):

import json
from django.shortcuts import render
from .models import Expense
from django.db.models import Sum

def home(request):
    records = Expense.objects.all().order_by('-date')
    total_cost = records.aggregate(Sum('price'))['price__sum'] or 0

    # 聚合各分類消費小計 (製作 Chart.js 數據)
    category_data = (
        Expense.objects.values('category')
        .annotate(total=Sum('price'))
        .order_by('-total')
    )
    
    chart_labels = [c['category'] for c in category_data]
    chart_values = [c['total'] for c in category_data]

    context = {
        'records': records,
        'total_cost': total_cost,
        'chart_labels': json.dumps(chart_labels, ensure_ascii=False), # 序列化為 JSON 字串給前端
        'chart_values': json.dumps(chart_values),
    }
    return render(request, 'expenses/home.html', context)

2. HTML Canvas 圖表渲染 (`templates/expenses/home.html`):

<!-- 引入 Chart.js CDN -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

<!-- 圖表展示卡片 -->
<div class="card shadow-sm border-0 mb-4">
    <div class="card-header bg-white fw-bold py-3">📊 消費分類比例圓餅圖</div>
    <div class="card-body" style="max-height: 300px; position: relative;">
        <canvas id="categoryChart"></canvas>
    </div>
</div>

<script>
    const ctx = document.getElementById('categoryChart').getContext('2d');
    const labels = {{ chart_labels|safe }};
    const dataValues = {{ chart_values|safe }};

    new Chart(ctx, {
        type: 'pie', // 圓餅圖
        data: {
            labels: labels,
            datasets: [{
                data: dataValues,
                backgroundColor: ['#0284c7', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6']
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false
        }
    });
</script>

3. 雲端上線設定檔 (`myproject/settings.py`):

# ⚠️ 上線前安全設定
DEBUG = False # 關閉黃底詳細報錯頁面

# 允許存取的域名 (加入你的 PythonAnywhere 網址)
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '.pythonanywhere.com']

# 靜態檔案收集目錄
STATIC_ROOT = BASE_DIR / 'staticfiles'

【學生自主實作框架】請根據今日各單元所學,將空缺的 `____` 填入正確的 Chart.js 與部署關鍵字:

<!-- 🎯 Day 10 自主挑戰:請填入 HTML 與 settings.py 空缺的 ____ 關鍵字! -->

<!-- --- [檔案: templates/expenses/home.html] --- -->
<!-- 1. 繪製圖表的 HTML5 畫布標籤 -->
<____ id="categoryChart"></____> # 提示:HTML5 圖表畫布標籤 canvas

<script>
    // 2. 避免 DTL 轉義 JSON 字串的過濾器
    const labels = {{ chart_labels|____ }}; # 提示:讓字串不被自動轉義的 filter: safe
    const dataValues = {{ chart_values|safe }};

    new Chart(ctx, {
        type: '____', # 提示:圓餅圖型態 pie
        data: { labels: labels, datasets: [{ data: dataValues }] }
    });
</script>

# --- [檔案: myproject/settings.py] ---
# 3. 關閉除錯保護機密
DEBUG = ____ # 提示:上線時需設定為 False

# 4. 允許連線的網域
ALLOWED_HOSTS = ['*']

⏰ 單元 1:前端進階:資料視覺化 (Chart.js)(09:00 - 10:00)

📊 故事單元說明:理財數據圓餅圖 (Chart.js)

單看表格數字太枯燥了!我們要引入著名的 JavaScript 第三方圖表庫 **Chart.js**。我們在 Django View 端使用 ORM 的 .values('category').annotate(total=Sum('price')) 將各分類花費小計算好,序列化成 JSON 傳給前端,並在 HTML 用 {{ chart_labels|safe }} 渲染成炫酷的圓餅圖!

💡 深度觀念:ORM Group By 聚合與前端 JavaScript 傳參

後端數據統計與前端圖表渲染的溝通橋樑:

  • ORM values().annotate():相當於 SQL 中的 GROUP BY category,高效率計算各分類總額。
  • DTL |safe 過濾器:預防 Django 自動轉義將 JSON 中的雙引號轉為 `"` 導致 JS 解析失敗。

🔗 Google 搜尋關鍵字 (依相關度排序,紫羅蘭標記為進階內容,點擊開啟新分頁):

🤖 AI 自主學習探索提示詞 (Prompt):

探索 Prompt (點擊複製)

請說明如何使用 Django ORM 的 annotate(Sum('price')) 進行分類聚合統計,並示範如何將資料轉換為 JSON 傳給前端 Chart.js 繪製圓餅圖。

🎓 教師備課手冊 (Teacher Only)
  • 在 View 使用 values('category').annotate(total=Sum('price')) 算統計。
  • 在 HTML 引入 Chart.js CDN 並放置 <canvas id="categoryChart">
  • 強調 DTL 管道符 {{ chart_labels|safe }} 的作用。
💻 HTML 與 JS 圖表段落
<!-- HTML5 畫布標籤 -->
<canvas id="categoryChart" width="400" height="200"></canvas>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
    const ctx = document.getElementById('categoryChart').getContext('2d');
    new Chart(ctx, {
        type: 'pie',
        data: {
            labels: {{ chart_labels|safe }},
            datasets: [{ data: {{ chart_values|safe }} }]
        }
    });
</script>
⚠️ 常見陷阱與問題案例
  • JS 語法錯誤 (Uncaught SyntaxError):在 HTML 中忘記加 `|safe`,導致傳過去的 JSON 被自動轉義為 `["餐飲"]` 造成 JS 當機。
🤖 單元 1 常見問題 AI 協作除錯提示詞

我在用 Chart.js 畫圖時主控台跳出了 Uncaught SyntaxError: Unexpected token '&' 錯誤。請提醒我如何在 DTL 變數加上 |safe 過濾器。

⏰ 單元 2:上線前置準備 (requirements.txt & .env)(10:00 - 11:00)

🧳 故事單元說明:打包行李箱與安全鎖 (.env & DEBUG)

要把網站上傳給雲端主機執行前,我們必須幫專案打包「行李箱」!執行 pip freeze > requirements.txt 生成套件清單,讓雲端主機知道需要安裝哪些庫。並且在 settings.pyDEBUG = False 鎖上黃底報錯頁面,預防駭客看光光我們的底層檔案路徑!對應 Day 5 的專案打包!

💡 深度觀念:為什麼 Production 環境必須關閉 DEBUG?

開發環境 (Development) 與正式上線環境 (Production) 的設定安全:

  • DEBUG = False:隱藏詳細 Traceback 與資料庫查詢資訊,防止機密外洩。關閉後必須指定 ALLOWED_HOSTS
  • requirements.txt:記錄所有依靠套件(如 `Django==4.2`),雲端伺服器憑此自動還原環境。

🔗 Google 搜尋關鍵字 (依相關度排序,紫羅蘭標記為進階內容,點擊開啟新分頁):

🤖 AI 自主學習探索提示詞 (Prompt):

探索 Prompt (點擊複製)

請說明在將 Django 部署上線前,為什麼必須執行 pip freeze > requirements.txt,以及將 DEBUG 設定為 False 後為什麼必須同時設定 ALLOWED_HOSTS。

🎓 教師備課手冊 (Teacher Only)
  • 執行 pip freeze > requirements.txt
  • settings.py 修改 DEBUG = FalseALLOWED_HOSTS = ['*']
  • 概念連結:對應 Day 5 專案打包與部署清單準備。
💻 Terminal 指令與 settings.py 安全設定
# 1. 匯出套件相依清單
pip freeze > requirements.txt

# 2. 修改 myproject/settings.py
DEBUG = False
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '.pythonanywhere.com', '.onrender.com']
⚠️ 常見陷阱與問題案例
  • CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False:將 DEBUG 改為 False 後,如果忘記設定 `ALLOWED_HOSTS`,伺服器會拒絕啟動!
🤖 單元 2 常見問題 AI 協作除錯提示詞

我在將 DEBUG 設定為 False 後跳出了 CommandError: You must set settings.ALLOWED_HOSTS。請教我如何在 settings.py 設定 ALLOWED_HOSTS = ['*']。

⏰ 單元 3:雲端部署平台介紹 (PaaS)(11:00 - 12:00)

☁️ 故事單元說明:租用 24hr 不打烊雲端主機 (PaaS)

如果我們的網站只放在本機,電腦關機網站就死掉了。我們需要將專案託管到 **PaaS (平台即服務)** 雲端主機平台(如 PythonAnywhere 或 Render)!雲端主機就是一部 24 小時不斷電的 Linux 電腦,能給我們一串真正的專屬網址,讓全世界隨時連線!

💡 深度觀念:IaaS vs PaaS vs SaaS 雲端架構

了解現代雲端架構分工:

  • PaaS (Platform as a Service):如 PythonAnywhere、Render,雲端廠商幫你維護好作業系統與 Python 環境,你只需上傳代碼。
  • WSGI 網關:雲端伺服器 (Web Server) 透過 WSGI 協定(如 Gunicorn / uWSGI)呼叫你的 Django 應用。

🔗 Google 搜尋關鍵字 (依相關度排序,紫羅蘭標記為進階內容,點擊開啟新分頁):

🤖 AI 自主學習探索提示詞 (Prompt):

探索 Prompt (點擊複製)

請向初學者說明什麼是 PaaS 雲端平台 (如 PythonAnywhere / Render),以及為什麼將 Django 專案部署到雲端主機後就能獲得公網網址。

🎓 教師備課手冊 (Teacher Only)
  • 帶學生註冊 PythonAnywhere 或 Render 免費帳號。
  • 講解網址概念:將 127.0.0.1 轉換為公網域名 username.pythonanywhere.com
  • 概念連結:突破 localhost 本地端限制,邁向網際網路。
💻 雲端平台註冊與連線檢查清單
# 雲端部署前準備清單:
[✓] 1. GitHub 帳號 / 代碼倉庫已建立 (或 zip 打包準備好)
[✓] 2. PythonAnywhere / Render 免費帳號已註冊完成
[✓] 3. 專案根目錄包含成功的 requirements.txt 檔案
[✓] 4. settings.py 已修改 DEBUG = False 與 ALLOWED_HOSTS
⚠️ 常見陷阱與問題案例
  • 雲端 Python 版本不符:本機用 Python 3.11 雲端預設用 3.8 $\rightarrow$ 在雲端平台設定檔中選取與本機相近的 Python 版本。
🤖 單元 3 常見問題 AI 協作除錯提示詞

我在雲端平台建立 Web App 時該如何選擇 Python 版本?請教我如何檢查本機與雲端的 Python 版本相容性。

⏰ 單元 4:實戰部署 (Deployment)(13:00 - 14:00)

🚚 故事單元說明:專案搬家上雲與 Cloud Migrate

我們將程式碼上傳到雲端伺服器(透過 Git/GitHub 或 Zip 上傳)。接著在雲端主機的 Bash Console 裡面,建立虛擬環境、執行 pip install -r requirements.txt 安裝套件,並執行 python manage.py migrate!在雲端伺服器實體建造屬於雲端環境的 SQLite 資料庫!

💡 深度觀念:雲端部署流程與版本控制

標準的軟體部署 (Deployment) 流程:

  • Git Clone 拉取代碼:透過 git clone https://github.com/... 將代碼無縫複製至雲端伺服器。
  • 雲端資料庫 Migrate:正式環境必須在雲端機器獨立執行 migrate 建立 SQLite 或雲端 PostgreSQL 資料庫。

🔗 Google 搜尋關鍵字 (依相關度排序,紫羅蘭標記為進階內容,點擊開啟新分頁):

🤖 AI 自主學習探索提示詞 (Prompt):

探索 Prompt (點擊複製)

請說明將 Django 專案部署上雲端時,在雲端主機的 Console 裡面執行 pip install -r requirements.txt 與 python manage.py migrate 的作用。

🎓 教師備課手冊 (Teacher Only)
  • 輔導學生將代碼上傳/Cloned 至雲端主機。
  • 在雲端 Console 建立虛擬環境與執行 pip install -r requirements.txt
  • 執行 python manage.py migrate 建立雲端資料庫。
  • 概念連結:對應 Day 5 軟體工程發布與出版流程。
💻 雲端 Console 常用部署指令段落
# 在雲端伺服器 (如 PythonAnywhere Bash) 內部執行:
# 1. 下載套件相依
pip install -r requirements.txt

# 2. 執行資料庫遷移
python manage.py migrate

# 3. 建立雲端超級管理員
python manage.py createsuperuser
⚠️ 常見陷阱與問題案例
  • 500 Internal Server Error:雲端忘記執行 `migrate` 導致資料庫無表格,或是 WSGI 檔案路徑設定錯誤。
🤖 單元 4 常見問題 AI 協作除錯提示詞

我的 Django 網站部署到雲端後出現 500 Internal Server Error。請教我如何查看雲端主機的 server.log 日誌找出出錯原因。

⏰ 單元 5:靜態檔案與除錯 (collectstatic)(14:00 - 15:00)

🎨 故事單元說明:雲端外觀收集與極限除錯 (collectstatic)

當我們開啟雲端網址時,突然發現「網站怎麼變回醜醜的純文字,Bootstrap CSS 完全失效了?」。因為當 DEBUG = False 時,Django 為了效能不會自動處理 CSS/JS!我們必須在 settings.py 設定 STATIC_ROOT,並執行 python manage.py collectstatic 把所有靜態裝潢打包在一起交給雲端 Web Server 處理!

💡 深度觀念:為什麼 Production 環境需要 collectstatic?

靜態檔案 (Static Files) 在正式環境的高效管理:

  • collectstatic 指令:將分散在各 App 目錄中的 CSS, JS, Image 圖檔統一複製收集至 STATIC_ROOT 指定資料夾。
  • WhiteNoise 套件:讓 Django 在 Production 模式下也能直接高效託管靜態檔案的熱門套件。

🔗 Google 搜尋關鍵字 (依相關度排序,紫羅蘭標記為進階內容,點擊開啟新分頁):

🤖 AI 自主學習探索提示詞 (Prompt):

探索 Prompt (點擊複製)

請說明當 DEBUG = False 時,為什麼 Django 網頁上的 CSS/JS 樣式會失效,以及如何設定 STATIC_ROOT 並執行 collectstatic 指令解決問題。

🎓 教師備課手冊 (Teacher Only)
  • settings.py 加入 STATIC_ROOT = BASE_DIR / 'staticfiles'
  • 在雲端 Console 執行 python manage.py collectstatic
  • 在 PythonAnywhere 的 Static Files 設定頁配對 `/static/` 路徑。
  • 概念連結:極限壓力測試與 Live 除錯能力。
💻 STATIC_ROOT 設定與收集指令
# 1. settings.py 設定靜態根目錄
STATIC_ROOT = BASE_DIR / 'staticfiles'

# 2. 雲端 Console 執行收集指令
python manage.py collectstatic --noinput
⚠️ 常見陷阱與問題案例
  • 網頁排版變純文字無樣式:雲端平台的 Web 頁面沒有手動在 Static files 表格加入 `/static/` 對應至 `staticfiles` 目錄。
🤖 單元 5 常見問題 AI 協作除錯提示詞

我的 Django 網站上線後 CSS 樣式都不見了。請教我如何在 PythonAnywhere 的 Static Files 設定欄位填寫 URL (/static/) 與 Directory 路徑。

⏰ 單元 6:🎓 Demo Day 成果發表會(15:00 - 16:00)

🏆 故事單元說明:理財全棧工程師雲端發布會

恭喜所有人登頂大圓滿!從一開始連 Python 都沒碰過的初學者,到現在擁有自己的雲端網址(如 xxx.pythonanywhere.com)!請上台秀出你的專屬網址、現場用手機連線記帳、向大家展示你的 **Chart.js 圓餅圖** 與 **Bootstrap 5 質感介面**!互相體驗同儕的作品,領取理財全棧工程師結業證書!

🎓 教師備課手冊 (Teacher Only)
  • 引導每位學生貼出個人專屬雲端 URL。
  • 邀請學生輪流上台 Live 操作展示(展示圖表、新增、刪除、搜尋)。
  • 頒發 30 小時 Python & Django 理財全棧營隊結業證書,拍照留念!
  • 概念連結:敏捷開發 Sprint Demo 與工程團隊分享文化。
💻 畢業檢查點與成果分享
# 🎓 30 小時全棧營隊終極畢業檢查點:
[✓] 1. 成功取得個人公網網址 (如 xxx.pythonanywhere.com)。
[✓] 2. 網站能繪製 Chart.js 分類比例圓餅圖。
[✓] 3. 網頁表單能在雲端資料庫新增與刪除消費紀錄。
[✓] 4. 成功解鎖跨越 CLI 到 Web 全棧開發者成就!
⚠️ 常見陷阱與問題案例
  • 現場展示突發連線問題:冷靜檢查雲端主機 Status 是否為 Active,或是 Console 重新 reload 網頁伺服器。
🤖 單元 6 常見問題 AI 協作除錯提示詞

請扮演一位充滿熱情的資深軟體架構師,針對一位成功完成 30 小時課程並將 Django 記帳網站部署至雲端的學生,寫一段 100 字的畢業賀詞,肯定他從 CLI 到 Web 的學習毅力與成果。