【问题标题】:The default "delete selected" admin action in DjangoDjango 中默认的“删除选定”管理操作
【发布时间】:2010-12-06 15:40:49
【问题描述】:

如何在 Django 管理面板中删除或更改默认管理操作“删除选定的 X 项”的详细名称?

【问题讨论】:

    标签: django django-admin


    【解决方案1】:

    作为 Googol 解决方案的替代方案,通过等待 delete_model() 到 be implemented in current Django version ,我建议使用以下代码。

    它仅禁用当前 AdminForm 的默认删除操作。

    class FlowAdmin(admin.ModelAdmin):
        actions = ['delete_model']
    
        def get_actions(self, request):
            actions = super(MyModelAdmin, self).get_actions(request)
            del actions['delete_selected']
            return actions
    
        def delete_model(self, request, obj):
            for o in obj.all():
                o.delete()
        delete_model.short_description = 'Delete flow'
    
    admin.site.register(Flow, FlowAdmin)
    

    【讨论】:

    • delete_model 不应使用,因为从管理员删除一个实例时会使用此方法。在这种情况下,queryset 参数不是一个查询集,它是一个实例,它会使循环崩溃。
    • 这个应该被选为接受的答案。
    • 我正在使用 django 1.4.16 和 delete_model 似乎在这两种情况下都有效(没有异常或循环)。
    【解决方案2】:

    您可以使用此代码禁止该操作出现。

    from django.contrib import admin
    admin.site.disable_action('delete_selected')
    

    如果您选择,您可以使用以下方法在单个模型上恢复它:

    class FooAdmin(admin.ModelAdmin):
        actions = ['my_action', 'my_other_action', admin.actions.delete_selected]
    

    【讨论】:

    • 在 Django 1.6 中也使用 'delete_selected' 而不是 admin.actions.delete_selected 工作正常。
    【解决方案3】:

    不确定这种猴子修补是否是一个好主意,但将它推到我的admin.py 之一对我有用:

    from django.contrib.admin.actions import delete_selected
    delete_selected.short_description = u'How\'s this for a name?'
    

    这将更改您的管理站点所有的详细名称。如果您只想为某个特定模型的管理员更改它,我认为您需要写一个custom admin action

    使用 Django 1.1 版测试:

    >>> import django
    >>> django.VERSION
    (1, 1, 0, 'beta', 1)
    

    【讨论】:

    • 对我来说似乎是一种聪明的方法,但它不起作用。它只是删除了操作框。
    • 嗯。我用 Django 1.1 对其进行了测试,它工作正常。我把它放在我的 admin.py 的顶部(在其他导入语句的下方)。
    • 对我来说是 (1 , 1, 0,'final', 0),也许这就是原因 :(
    • Dominic & Hellnar:确保升级到 1.1.0 以上,有一个紧急的安全修复程序,其中包含野外漏洞。该问题已在 1.1.1 和 1.0.4 中修复。详情在这里:djangoproject.com/weblog/2009/oct/09/security
    • 我对此表示怀疑 - 我通过查看主干的来源(特别是 code.djangoproject.com/browser/django/trunk/django/contrib/…)猜到了这个想法。
    【解决方案4】:

    为了替换 delete_selected 我执行以下操作:

    将函数 delete_selectedcontrib/admin/actions.py 复制到您的 admin.py 并重命名。还将模板contrib/admin/templates/delete_selected_confirmation.html 复制到您的模板目录并重命名。我的看起来像这样:

    def reservation_bulk_delete(modeladmin, request, queryset):
        """
        Default action which deletes the selected objects.
        This action first displays a confirmation page whichs shows all the
        deleteable objects, or, if the user has no permission one of the related
        childs (foreignkeys), a "permission denied" message.
    
        Next, it delets all selected objects and redirects back to the change list.
        """
        opts = modeladmin.model._meta
        app_label = opts.app_label
    
        # Check that the user has delete permission for the actual model
        if not modeladmin.has_delete_permission(request):
            raise PermissionDenied
    
        # Populate deletable_objects, a data structure of all related objects that
        # will also be deleted.
    
        # deletable_objects must be a list if we want to use '|unordered_list' in the template
        deletable_objects = []
        perms_needed = set()
        i = 0
        for obj in queryset:
            deletable_objects.append([mark_safe(u'%s: <a href="%s/">%s</a>' % (escape(force_unicode(capfirst(opts.verbose_name))), obj.pk, escape(obj))), []])
            get_deleted_objects(deletable_objects[i], perms_needed, request.user, obj, opts, 1, modeladmin.admin_site, levels_to_root=2)
            i=i+1
    
        # The user has already confirmed the deletion.
        # Do the deletion and return a None to display the change list view again.
        if request.POST.get('post'):
            if perms_needed:
                raise PermissionDenied
            n = queryset.count()
            if n:
                for obj in queryset:
                    obj_display = force_unicode(obj)
    
                    obj.delete()
    
                    modeladmin.log_deletion(request, obj, obj_display)
                #queryset.delete()
                modeladmin.message_user(request, _("Successfully deleted %(count)d %(items)s.") % {
                    "count": n, "items": model_ngettext(modeladmin.opts, n)
                })
            # Return None to display the change list page again.
            return None
    
        context = {
            "title": _("Are you sure?"),
            "object_name": force_unicode(opts.verbose_name),
            "deletable_objects": deletable_objects,
            'queryset': queryset,
            "perms_lacking": perms_needed,
            "opts": opts,
            "root_path": modeladmin.admin_site.root_path,
            "app_label": app_label,
            'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
        }
    
        # Display the confirmation page
        return render_to_response(modeladmin.delete_confirmation_template or [
            "admin/%s/%s/reservation_bulk_delete_confirmation.html" % (app_label, opts.object_name.lower()),
            "admin/%s/reservation_bulk_delete_confirmation.html" % app_label,
            "admin/reservation_bulk_delete_confirmation.html"
        ], context, context_instance=template.RequestContext(request))
    

    如你所见,我注释掉了

    queryset.delete()
    

    宁可使用:

    obj.delete()
    

    这还不是最优的——你应该对整个查询集应用一些东西以获得更好的性能。

    在 admin.py 中,我禁用了整个管理站点的默认操作 delete_selected:

    admin.site.disable_action('delete_selected')
    

    相反,我在需要时使用我自己的函数:

    class ReservationAdmin(admin.ModelAdmin):
        actions = [reservation_bulk_delete, ]
    

    在我的模型中,我定义了delete() 函数:

    class Reservation(models.Model):
        def delete(self):
            self.status_server = RESERVATION_STATUS_DELETED
            self.save()
    

    【讨论】:

      【解决方案5】:

      对于全局更改 delete_selected 的 short_description Dominic Rodgeranswer 似乎最好。

      但是,对于在管理员上为单个模型更改 short_description,我认为Stéphaneanswer 的替代方案更好:

      def get_actions(self, request):
          actions = super().get_actions(request)
          actions['delete_selected'][0].short_description = "Delete Selected"
          return actions
      

      【讨论】:

      • 太棒了!有效!
      【解决方案6】:
      【解决方案7】:
      from django.contrib.admin import sites
      from django.contrib.admin.actions import delete_selected
      
      
      class AdminSite(sites.AdminSite):
          """
          Represents the administration, where only authorized users have access.
          """
          def __init__(self, *args, **kwargs):
              super(AdminSite, self).__init__(*args, **kwargs)
              self.disable_action('delete_selected')
              self.add_action(self._delete_selected, 'delete_selected')
      
          @staticmethod
          def _delete_selected(modeladmin, request, queryset):
              _delete_qs = queryset.delete
      
              def delete():
                  for obj in queryset:
                      modeladmin.delete_model(request, obj)
                  _delete_qs()
      
              queryset.delete = delete
              return delete_selected(modeladmin, request, queryset)
      

      【讨论】:

        【解决方案8】:
        class FooAdmin(sites.AdminSite):
                not_deleted = ['value1', 'value2']
                actions = ['delete_selected_values']
        
            def delete_selected_values(self, request, queryset):
                # my custom logic
                exist = queryset.filter(value__in=self.not_deleted).exists()
                if exist:
                    error_message = "Error"
                    self.message_user(request, error_message, level=messages.ERROR)
                else:
                    delete_action = super().get_action('delete_selected')[0]
                    return delete_action(self, request, queryset)
            delete_selected_values.short_description = 'delete selected'
        
        admin.site.register(Foo, FooAdmin)
        

        【讨论】:

        • 欢迎来到 StackOverflow!请评论您的代码
        猜你喜欢
        • 2016-03-13
        • 1970-01-01
        • 2022-12-20
        • 1970-01-01
        • 1970-01-01
        • 2018-02-08
        • 2016-11-02
        • 1970-01-01
        • 2011-06-05
        相关资源
        最近更新 更多