You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django 4.2 ModelAdmin单对象删除失败时如何屏蔽成功提示?

单个删除失败却同时显示成功/失败提示的问题排查与解决

问题描述

在Django 4.2的ModelAdmin中自定义了删除逻辑,批量删除时失败提示显示正常,但单个删除(经confirm_delete.html确认后)明明删除失败(符合预期),页面却同时弹出成功和失败两种提示。

原因分析

  1. delete_model方法缩进错误,未被重写
    你提供的代码中,delete_model是全局函数而非ModelAdmin类的成员方法,Django会忽略这个自定义逻辑,转而执行默认的delete_model——默认逻辑会直接删除数据库中的对象,导致response_delete检测到对象不存在时弹出成功提示。

  2. 自定义API删除逻辑未关联数据库删除动作
    即使修复缩进,当前delete_model在API删除成功时未调用obj.delete(),数据库对象不会被删除,response_delete会误判为删除失败;而API删除失败时,默认逻辑(如果未被正确覆盖)仍会删除数据库对象,导致成功提示和自定义的失败提示同时出现。

  3. response_delete判断逻辑脱离实际删除结果
    当前response_delete仅通过数据库中是否存在对象判断删除状态,未关联API的实际返回结果,导致状态判断不准确。

修复方案

步骤1:修复delete_model的缩进

将delete_model缩进至ModelAdmin类内部,确保Django识别并使用自定义逻辑。

步骤2:完善delete_model逻辑

在API删除成功后手动删除数据库对象,失败时保留对象并添加错误提示,所有状态提示直接在delete_model中处理,避免response_delete重复判断。

步骤3:简化response_delete

仅保留跳转逻辑,删除原本的状态判断和提示添加,因为结果已在delete_model中处理完毕。

完整修复代码

class MailboxAdmin(admin.ModelAdmin):
    # 其他配置...

    def get_actions(self, request):
        actions = super().get_actions(request)        
        del actions['delete_selected']
        return actions

    def really_delete_selected(self, request, queryset):
        '''
        # 1. Update the group-mailbox relation: `goto` values if mailbox(es) are deleted
        # 2. Sending a mail to the current user with CSV of mailboxes deleted
        # 3. Used domain space will reduce by the maxquota of mailbox
        '''
        response = None
        try:
            mbox_list = []
            failed_deletions = []
            for obj in queryset:
                # COMPLETE MAILBOX DELETION OF FOLDERS, DOVECOT ENTRY, ADMIN PANEL PERMANENTLY 
                api_delete_status = call_purge_mailbox_api(request, obj)
                response = api_delete_status
                if response['status_code'] == 200:
                    # Set the quota value after deletion of mailbox(es)
                    mdomain = Domain.objects.get(id=obj.domain.pk)
                    mdomain.quota -= obj.maxquota
                    mdomain.save()
                    mbox_list.append(obj.email) 
                    # Remove the user from the group mailing lists
                    removed_from_groups = remove_from_group_lists(obj.email, mbox_list)
                    # 删除数据库中的对象
                    obj.delete()
                else:
                    failed_deletions.append(obj.email)
 
            if mbox_list:
                self.message_user(request, f"Successfully deleted {len(mbox_list)} mailbox(es).", level='success')
            for email in failed_deletions:
                self.message_user(request, f"Failed to delete {email}. Mailbox absent. Contact helpdesk.", level='error')
            if not mbox_list and not failed_deletions:
                self.message_user(request, "No mailboxes were selected for deletion.", level='error')
        except Exception as e:
            self.message_user(request, f"Failed to delete items: {str(e)}", level='error')
    really_delete_selected.short_description = "Delete selected entries"

    def delete_model(self, request, obj):
        try:
            # Perform the deletion via API
            api_delete_status = call_purge_mailbox_api(request, obj)
            if isinstance(api_delete_status, dict) and 'status_code' in api_delete_status:
                status_code = api_delete_status['status_code']
                if status_code == 200:
                    # API删除成功,再删除数据库对象
                    mdomain = Domain.objects.get(id=obj.domain.pk)
                    mdomain.quota -= obj.maxquota
                    mdomain.save()
                    # Remove the user from the group mailing lists
                    removed_from_groups = remove_from_group_lists(obj.email, [obj])
                    obj.delete()
                    self.message_user(request, f"Successfully deleted {obj.email}.", level='success')
                else:
                    # API删除失败,保留数据库对象并提示错误
                    self.message_user(request, f"Failed to delete mailbox {obj.email}. Contact Helpdesk", level='error')
            else:
                self.message_user(request, f"Invalid response from deletion API for {obj.email}.", level='error')
        except Exception as e:
            self.message_user(request, f"Failed to delete {obj.email}. Error: {str(e)}", level='error')

    def response_delete(self, request, obj_display, obj_id):
        # 仅跳转回列表页,提示已在delete_model中处理
        return HttpResponseRedirect(reverse('admin:myapp_mailbox_changelist'))

关键说明

  • 修复缩进后,delete_model会被Django正确调用,替代默认逻辑。
  • API删除成功后才调用obj.delete(),确保数据库对象和实际邮箱资源同步删除。
  • 所有提示信息都在delete_model和really_delete_selected中处理,response_delete仅负责跳转,避免重复判断导致的错误提示。
  • 批量删除的really_delete_selected中也添加了obj.delete(),确保数据库对象被同步删除。

内容的提问来源于stack exchange,提问作者user956424

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 11:25:56