iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
Claude AI

從零開始 Claude Code:30 天打造 AI 任務管理 Web App系列 第 15 篇

[Day 15] 把基本 CRUD 補完整:加入刪除任務

  • 分享至 

  • xImage
  •  

Day 14 已經完成任務編輯。
目前 CRUD 已經有:

Create
→ 新增任務

Read
→ 顯示任務

Update
→ 編輯任務

今天要補上最後一塊:

Delete
→ 刪除任務

Day 15 的目標很單純:
讓首頁上的任務可以被刪除,而且真的同步刪掉 MySQL 裡的資料。


今天的範圍

今天只做:

首頁按「刪除」
	↓
跳出確認視窗
	↓
送出 POST
	↓
Flask 找到指定 Task
	↓
從 MySQL 刪除
	↓
  回首頁

今天先不做:

篩選
快速切換狀態
分類 CRUD
services/
routes/
Claude API

先讓 Claude Code 規劃

我先把需求交給 Claude Code:

目前狀態:

 1. /tasks/new 可以新增任務
 2. 首頁可以從 MySQL 讀取任務
 3. /tasks/<task_id>/edit 可以編輯任務
 4. Task CRUD 已經完成 Create / Read / Update

今天只做「刪除任務」。

需求:

1. 首頁每張任務卡片增加「刪除」按鈕
2. 使用 POST 送出刪除請求
3. Flask 根據 task_id 找到任務
4. 找不到任務時回 404
5. 找到後用 db.session.delete(task)
6. db.session.commit()
7. 刪除成功後 redirect 回首頁
8. 不使用 GET 直接刪除資料
9. 加入瀏覽器原生 confirm(),避免誤刪

今天不要:
- 篩選
- 快速切換狀態
- 分類 CRUD
- services/
- routes/
- Claude API

請先規劃會修改哪些檔案,
不要直接修改程式。

最後只修改:

app.py
templates/index.html
static/css/style.css

不需要新增新的頁面,也不用修改資料庫結構。


app.py:新增刪除 Route

這次新增:

@app.route("/tasks/<int:task_id>/delete", methods=["POST"])
def delete_task(task_id):
    task = Task.query.get_or_404(task_id)

    db.session.delete(task)
    db.session.commit()

    return redirect(url_for("index"))

這段就是 Day 15 最核心的程式。


task_id 還是負責指定哪一筆任務

例如首頁有:

id = 3
title = 測試1

按下這筆任務的刪除按鈕後,會送到:

/tasks/3/delete

所以 Flask 收到:

task_id = 3

接著:

task = Task.query.get_or_404(task_id)

去 MySQL 找:

id = 3

那筆資料。
如果找不到,就直接回:

404 Not Found

db.session.delete() 是什麼?

Day 12 新增資料時,用的是:

db.session.add(task)

Day 15 刪除則是:

db.session.delete(task)

可以理解成:

add()
→ 準備新增

delete()
→ 準備刪除

但真正把變更寫進 MySQL,還是要:

db.session.commit()

所以:

找到 Task
	 ↓
delete(task)
	 ↓
commit()
	 ↓
MySQL DELETE

為什麼是 POST,不是 DELETE?

這裡我原本也有疑問。
既然做的是「刪除」,為什麼 Route 是:

@app.route("/tasks/<int:task_id>/delete", methods=["POST"])

不是:

DELETE

原因是目前這個專案使用一般的 HTML <form>。
原生 HTML form 主要支援:

GET
POST

不能直接這樣寫:

<form method="DELETE">

所以目前 Flask + Jinja2 的做法,直接使用:

POST /tasks/3/delete

會比較簡單。
如果未來改成 REST API,可能會使用:

DELETE /tasks/3

例如搭配 JavaScript:

fetch("/tasks/3", {
    method: "DELETE"
})

但目前專案沒有使用 AJAX,所以 Day 15 繼續用 POST。
可以簡單記成:

目前 HTML 表單網站
→ POST /tasks/3/delete

REST API 常見寫法
→ DELETE /tasks/3

為什麼不能用 GET 刪除?

如果寫成:

GET /tasks/3/delete

只要有人打開網址,就會把資料刪掉。
但 GET 比較適合:

查看頁面
讀取資料

刪除會改變資料,所以不應該使用 GET。
這也是為什麼這次 Route 特別限定:

methods=["POST"]

index.html:加入刪除表單

首頁原本 Day 14 已經有:

<a
    class="edit-link"
    href="{{ url_for('edit_task', task_id=task.id) }}">
    編輯
</a>

Day 15 在旁邊加入:

<form
    class="delete-form"
    method="POST"
    action="{{ url_for('delete_task', task_id=task.id) }}"
    onsubmit="return confirm('確定要刪除這個任務嗎?');">

    <button class="delete-button" type="submit">
        刪除
    </button>
</form>

所以每張任務卡片現在都有:

編輯   刪除

https://ithelp.ithome.com.tw/upload/images/20260929/20183857LqfhM1ZNqG.png


confirm() 避免手滑

如果按一下就直接刪掉,太容易誤操作。
所以表單加上:

onsubmit="return confirm('確定要刪除這個任務嗎?');"

按下「刪除」後,瀏覽器會先跳出確認視窗。
也就是:

   刪除
	↓
confirm()
	↓
取消 → 不刪
確定 → 才送 POST

CSS:讓刪除按鈕跟編輯放在一起

這次新增:

.delete-form {
    display: inline-block;
    margin: 6px 0 0 12px;
}

因為 <form> 原本比較像區塊元素,這樣可以讓它跟「編輯」比較自然地排在一起。
刪除按鈕:

.delete-button {
    padding: 0;
    border: 0;
    background: none;
    color: var(--todo-text);
    font-size: 0.85rem;
    font-weight: 600;
}

再加:

.delete-button:hover {
    text-decoration: underline;
}

這樣就不會像一般大型按鈕,而是比較像文字操作。
目前刪除使用的是:

var(--todo-text)

所以會呈現偏橘色。
這不影響功能,之後如果想整理 CSS,可以再另外定義:

--danger

專門給刪除這類危險操作使用。


實際測試

我先在首頁確認每張任務都有:

編輯
刪除

接著按下「刪除」。
瀏覽器會先跳出:
https://ithelp.ithome.com.tw/upload/images/20260929/20183857Ek49R8lGRK.png
首頁重新整理後,該筆任務已經不在列表中。


MySQL 裡也真的刪掉了

接著回 MySQL Workbench:

SELECT * FROM tasks;

確認剛才刪掉的 Task 已經從 tasks 資料表消失。
這代表流程不是只有前端把卡片隱藏,而是真的:

  首頁
	↓
  POST
	↓
  Flask
	↓
SQLAlchemy
	↓
MySQL DELETE

資料庫裡也確實刪除成功。


刪除成功後為什麼會回首頁?

Route 最後:

return redirect(url_for("index"))

刪除完成後回到:

/

而 Day 13 的首頁本來就會重新查:

Task.query.order_by(
    Task.created_at.desc(),
    Task.id.desc(),
).all()

所以被刪掉的任務自然就不會再出現。


CRUD 終於完整了

做到 Day 15,任務已經有完整 CRUD:

Create
→ 新增任務

Read
→ 查看任務

Update
→ 編輯任務

Delete
→ 刪除任務

這時候這個 Web App 已經真的可以管理 MySQL 裡的 Task。
不是只有畫面,也不是假資料。
目前可以:

建立任務
查看任務
修改任務
刪除任務

而且每個動作都會同步到資料庫。


今天做到這裡

Day 15 完成後,Task 的基本 CRUD 已經補完整。
接下來不再只是「資料能不能新增修改」,而是開始處理任務本身的狀態管理。
目前資料庫其實已經有:

todo
in_progress
done

但首頁上方的:

全部
待處理
進行中
已完成

目前還只是畫面,沒有真的篩選資料。
下一步就開始處理這部分。


上一篇
[Day 14] 任務寫錯怎麼辦?加入編輯功能
下一篇
[Day 16] 任務不只新增刪除:開始管理狀態
系列文
從零開始 Claude Code:30 天打造 AI 任務管理 Web App 共 16 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言