Django 留言軟刪除邏輯|程式碼解析
更新日期: 2025 年 1 月 7 日
本文為 留言評分功能 系列教學,第 10 篇:
- 使用 Django + Tailwind + Alpine.js 實作「五顆星評分」功能教學
- Django validators 驗證器完整教學
- Django PositiveSmallIntegerField 新手指南
- 在 esbuild 專案中整合 Alpine.js 的完整指南
- 使用 Alpine.js 建立星星評分表單 — 新手指南
- 深入理解 Alpine.js 中的 template 標籤使用指南
- Django 網站如何新增「星星評分」功能 — 後端接收邏輯
- Django 表單:如何讓使用者選擇性提交星星評分與留言
- Django 如何限制同一使用者只能對同一服務留言一次?
- Django 留言軟刪除邏輯|程式碼解析 👈 所在位置
- Django 計算評分摘要教學 — 使用 ORM 進行星等統計
- Python Django 使用 annotate、aggregate 統計教學
- 使用 Alpine.js 實作星級評分分佈 – 詳細教學
- Alpine.js 與 Tailwind CSS 動態樣式解析:為什麼有些樣式無法生效?
- Django 中使用 annotate() 與 Avg() 進行平均評分計算
在 Django 專案中,有時我們希望在刪除資料時保留數據,而不是將其完全從資料庫中移除。
這種設計被稱為 軟刪除 (Soft Delete)。軟刪除能夠保留歷史記錄,方便進行數據審查或日後恢復。
本篇文章將深入解釋 Django 中的軟刪除邏輯,並逐步分析以下範例程式碼,幫助新手理解如何正確實作軟刪除功能。
什麼是軟刪除 (Soft Delete)?
軟刪除 是一種透過標記數據為已刪除的方式來實現刪除功能,但實際上數據仍然保留在資料庫中。
這與「硬刪除 (Hard Delete)」不同,後者會直接將數據從資料庫中永久移除。
軟刪除的設計:
is_deleted
:布林值,表示該筆資料是否被刪除。deleted_at
:時間戳記,記錄刪除的時間。is_deleted=True
→ 表示該筆資料已被軟刪除,但仍存在於資料庫中。
範例程式碼 (Django service_detail
視圖)
@login_required
def service_detail(request, id, service_id):
service = get_object_or_404(Service, id=service_id)
comments = Comment.objects.filter(service=service, is_deleted=False).order_by("-created_at")
# 嘗試取得使用者的評論
try:
comment = Comment.objects.get(service=service, user=request.user)
except Comment.DoesNotExist:
comment = None
# 初始化表單
form = CommentForm(request.POST or None, instance=comment)
# POST 請求處理
if request.method == "POST":
form = CommentForm(request.POST, instance=comment)
if form.is_valid():
comment = form.save(commit=False)
comment.user = request.user
comment.service = service
comment.rating = request.POST.get("rating")
comment.is_deleted = False
comment.deleted_at = None
comment.save()
return redirect("services:service_detail", id=request.user.id, service_id=service_id)
# 軟刪除檢查
if comment and comment.is_deleted:
comment = None
form = CommentForm()
return render(
request,
"services/service_detail.html",
{
"service": service,
"comments": comments,
"comment": comment,
"form": form,
},
)
嘗試取得使用者的評論
try:
comment = Comment.objects.get(service=service, user=request.user)
except Comment.DoesNotExist:
comment = None
解釋
- 嘗試透過
Comment.objects.get()
查詢該使用者是否已針對該服務發表過評論。 - 成功取得評論 →
comment
變數儲存該評論物件。 - 查無評論 → 捕捉
Comment.DoesNotExist
例外,並將comment
設為None
。
初始化表單
form = CommentForm(request.POST or None, instance=comment)
這行的閱讀方式可以拆解為:
request.POST or None
- 這部分是使用了 Python 的「短路求值」(short-circuit evaluation)。
- 如果
request.POST
存在且為 非空字典(表示用戶提交了表單數據),則使用request.POST
作為表單的輸入數據。 - 如果
request.POST
不存在(例如是 GET 請求,或表單沒有提交),則返回None
。
instance=comment
- 這是 Django 表單的關鍵參數,用於表示「要綁定的模型實例」。
- 如果
comment
物件存在,則表單會使用該comment
實例的數據進行初始化,並顯示原有的內容。 - 如果
comment
為None
,表單將以空白狀態初始化。
邏輯重點:短路求值
request.POST or None
短路求值解釋:
- 如果
request.POST
有值(通常是使用者提交的表單數據),則該值會被傳遞到CommentForm
中。 - 如果
request.POST
沒有值(例如 GET 請求),則傳遞None
。
更直觀的條件判斷版:
這行程式碼其實等同於以下邏輯:
if request.method == "POST":
form = CommentForm(request.POST, instance=comment) # 表單填入 POST 資料
else:
form = CommentForm(instance=comment) # 初始化空白表單或使用現有資料
示意圖:
+---------------------------+
| request.POST or None |
+------------+--------------+
|
+-------+-----------------------+
| POST 有數據嗎? |
+-------+-----------------------+
| YES | NO
v v
使用 request.POST 使用 None
初始化表單數據 初始化為空白表單
- 如果有 POST 資料:
- 表單會使用使用者提交的資料進行初始化,並綁定
comment
物件(如果存在)。
- 表單會使用使用者提交的資料進行初始化,並綁定
- 如果是 GET 請求(未提交資料):
- 表單會以
None
初始化,並根據comment
(如果存在)載入預設數據。
- 表單會以
表單提交與儲存資料
if request.method == "POST":
form = CommentForm(request.POST, instance=comment)
if form.is_valid():
comment = form.save(commit=False)
comment.user = request.user
comment.service = service
comment.rating = request.POST.get("rating")
comment.is_deleted = False
comment.deleted_at = None
comment.save()
return redirect("services:service_detail", id=request.user.id, service_id=service_id)
解釋
- 檢查是否為
POST
請求:只有在表單提交後才進行這部分邏輯。 form.is_valid()
:檢查表單數據是否通過 Django 驗證邏輯。- 儲存資料:
- 如果通過表單驗證,建立或更新
comment
。 - 將
is_deleted
設為False
(確保重新激活評論)。 - 將
deleted_at
設為None
(移除刪除標記)。
- 如果通過表單驗證,建立或更新
檢查軟刪除狀態並清空表單
if comment and comment.is_deleted:
comment = None
form = CommentForm()
解釋
- 如果
comment
存在且標記為已刪除 (is_deleted=True
):- 清空
comment
變數,並重新初始化一個空白表單。
- 清空
- 這確保已刪除的評論不會再次顯示。
完整流程圖 (包含 GET 與 POST)
總結:Django 軟刪除的完整邏輯
- 定義軟刪除欄位:使用
is_deleted
和deleted_at
欄位追蹤刪除狀態。 - 檢查使用者評論:透過
Comment.objects.get()
查找評論。 - 軟刪除邏輯:如果
is_deleted=True
,則重新初始化空白表單。 - 提交評論:表單提交時自動更新
is_deleted
和deleted_at
欄位狀態。
這種設計讓你的 Django 專案更具備數據保護與可恢復性,同時也能確保良好的使用者體驗。