Logo

新人日誌

首頁關於我部落格

新人日誌

Logo

網站會不定期發佈技術筆記、職場心得相關的內容,歡迎關注本站!

網站
首頁關於我部落格
部落格
分類系列文

© 新人日誌. All rights reserved. 2020-present.

Django 留言軟刪除邏輯|程式碼解析

最後更新:2025年1月7日Python

本文為 留言評分功能 系列教學,第 10 篇:

  1. 使用 Django + Tailwind + Alpine.js 實作「五顆星評分」功能教學
  2. Django validators 驗證器完整教學
  3. Django PositiveSmallIntegerField 新手指南
  4. 在 esbuild 專案中整合 Alpine.js 的完整指南
  5. 使用 Alpine.js 建立星星評分表單 — 新手指南
  6. 深入理解 Alpine.js 中的 template 標籤使用指南
  7. Django 網站如何新增「星星評分」功能 — 後端接收邏輯
  8. Django 表單:如何讓使用者選擇性提交星星評分與留言
  9. Django 如何限制同一使用者只能對同一服務留言一次?
  10. Django 留言軟刪除邏輯|程式碼解析 👈 所在位置
  11. Django 計算評分摘要教學 — 使用 ORM 進行星等統計
  12. Python Django 使用 annotate、aggregate 統計教學
  13. 使用 Alpine.js 實作星級評分分佈 – 詳細教學
  14. Alpine.js 與 Tailwind CSS 動態樣式解析:為什麼有些樣式無法生效?
  15. 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)

這行的閱讀方式可以拆解為:

  1. request.POST or None
    • 這部分是使用了 Python 的「短路求值」(short-circuit evaluation)。
    • 如果 request.POST 存在且為 非空字典(表示用戶提交了表單數據),則使用 request.POST 作為表單的輸入數據。
    • 如果 request.POST 不存在(例如是 GET 請求,或表單沒有提交),則返回 None。
  2. 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
  初始化表單數據        初始化為空白表單
  1. 如果有 POST 資料:
    • 表單會使用使用者提交的資料進行初始化,並綁定 comment 物件(如果存在)。
  2. 如果是 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 軟刪除的完整邏輯

  1. 定義軟刪除欄位:使用 is_deleted 和 deleted_at 欄位追蹤刪除狀態。
  2. 檢查使用者評論:透過 Comment.objects.get() 查找評論。
  3. 軟刪除邏輯:如果 is_deleted=True,則重新初始化空白表單。
  4. 提交評論:表單提交時自動更新 is_deleted 和 deleted_at 欄位狀態。

這種設計讓你的 Django 專案更具備數據保護與可恢復性,同時也能確保良好的使用者體驗。

目前還沒有留言,成為第一個留言的人吧!

發表留言

留言將在審核後顯示。

Python

目錄

  • 什麼是軟刪除 (Soft Delete)?
  • 軟刪除的設計:
  • 範例程式碼 (Django service_detail 視圖)
  • 嘗試取得使用者的評論
  • 解釋
  • 初始化表單
  • 邏輯重點:短路求值
  • 更直觀的條件判斷版:
  • 示意圖:
  • 表單提交與儲存資料
  • 解釋
  • 檢查軟刪除狀態並清空表單
  • 解釋
  • 完整流程圖 (包含 GET 與 POST)
  • 總結:Django 軟刪除的完整邏輯