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

更新日期: 2025 年 1 月 7 日

在 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 實例的數據進行初始化,並顯示原有的內容。
    • 如果 commentNone,表單將以空白狀態初始化。

邏輯重點:短路求值

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_deleteddeleted_at 欄位追蹤刪除狀態。
  2. 檢查使用者評論:透過 Comment.objects.get() 查找評論。
  3. 軟刪除邏輯:如果 is_deleted=True,則重新初始化空白表單。
  4. 提交評論:表單提交時自動更新 is_deleteddeleted_at 欄位狀態。

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

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *