py程式設計(三)課程網站
第 12 週 · 單元 5-1 · 換一套技術

同一份 PROJECT.md,換成 Next.js 重做吃貨站

第 4–5 週用 Flask 做的吃貨站,這兩週用 JavaScript 的 Next.js 再做一次。需求、資料表、驗收標準一字不改,你會發現:真正在工作的是六步建站法,技術只是工具。

W12Next.js同一份規格

本週結束時你會

今天的時間安排

0:00–0:25觀念:Flask 與 Next.js 的對照;Server Component 是什麼
0:25–1:00【跟著做】安裝 Node.js、建立專案、連上 Neon 開發分支
1:00–1:10休息
1:10–1:50功能 1【自己做】首頁排行榜,對答案
1:50–2:30功能 2【自己做】店家頁,對答案;週誌

Flask 與 Next.js 對照

要做的事Flask(第 4–5 週)Next.js(這兩週)
語言PythonJavaScript
一個網址對應一段程式@app.route("/shop/<int:id>")資料夾 app/shop/[id]/page.js
頁面Jinja 範本 templates/shop.htmlReact 元件(同一個 page.js 裡)
讀資料庫路由函式裡查詢,再交給範本Server Component 直接 await query(...)
表單送出@app.post 路由Server Action("use server")
SQL 參數?(SQLite)/%s(Postgres)$1、$2(Postgres)
本機資料庫SQLite 檔案Neon 的開發分支(連線字串放 .env.local)
部署Vercel(Python Function)Vercel(Next.js 是 Vercel 自家的框架,零設定)

Server Component:在伺服器上執行的 React 元件,可以直接查資料庫,查完再把 HTML 送給瀏覽器。資料庫連線字串永遠不會被送到使用者的瀏覽器。

準備環境【跟著做】

  1. 到 nodejs.org 下載 LTS 版安裝,裝好後重新開啟 Antigravity。
  2. Neon 開發分支:Vercel 的 Storage 頁面點進 Neon 管理後台 → Branches → 建立一個 dev 分支。開發用 dev,正式網站用 main,測試資料不會弄髒正式資料。
  3. 在 dev 分支的連線資訊中複製連線字串,只貼到專案的 .env.local(下一步建立),不要貼到對話框。
提示詞 1 Antigravity
請在「程式設計三」資料夾建立 Next.js 專案 foodie-next:使用 create-next-app 15 版、JavaScript(不要 TypeScript)、App Router、不要 Tailwind。
接著:
1. 複製我的吃貨站 PROJECT.md 進來,把「技術」改成 Next.js 15、Postgres(pg 套件)、Pico.css
2. 安裝 pg;建立 lib/db.js,從環境變數 DATABASE_URL 建立連線池,提供 query(sql, params) 函式,SQL 參數用 $1、$2
3. 建立 db/schema.sql(Postgres 語法)與 db/seed.sql(從 Flask 版的 seed.sql 轉換),以及 npm run init-db 指令
4. 建立 .env.example 說明需要哪些環境變數;我會自己建立 .env.local 並貼上連線字串
完成後告訴我下一步要做什麼。不要讀取或顯示 .env.local 的內容。
應該看到你自己建立 .env.local 後,執行 npm run init-db 顯示「shops 12 筆、reviews 49 筆」。

Flask 版 seed.sql 指定了店家 id,轉成 Postgres 後要把自動編號接到最大值之後,否則新增店家時會和既有的 id 衝突。參考解答在 seed.sql 最後用 setval 處理。若學生新增店家時出現 duplicate key 錯誤,就是漏了這一步,是很好的討論題材。

功能 1:首頁排行榜【自己做】

照吃貨站第 4 週的提示詞改寫:把「只修改 app.py 與 templates/」換成「只修改 app/page.js」,並說明要用 Server Component 直接查資料庫。

檢查正確結果(與第 4 週相同)
前五名派森牛肉湯、函式炒鱔魚、布林豆花、字典虱目魚粥、迴圈碗粿
最後一名模組肉燥飯,「尚無評分」
/?category=麵函式炒鱔魚、縮排鍋燒意麵、變數擔仔麵
巡堂重點:Postgres 的平均數

Postgres 的 AVG() 回傳的是 numeric,ROUND(AVG(rating), 1) 在某些寫法下會出錯,要寫成 ROUND(AVG(rating)::numeric, 1)。另外 pg 套件會把 numeric 以文字形式交給 JavaScript(例如 "4.7"),顯示沒問題,但拿來計算前要先轉成數字。

功能 2:店家頁【自己做】

網址正確結果
/shop/1★ 4.7(6 則評論),第一則是小林
/shop/12尚無評分
/shop/999、/shop/abc都是 404 頁面(不是錯誤畫面)

Next.js 15 的寫法提醒:頁面收到的 params 與 searchParams 要先 await 才能使用。AI 有時會用舊版寫法,出現相關警告時,把警告訊息貼給它。

本週檢核