Django Admin:has_delete_permission忽略“删除”操作

时间:2016-06-30 15:31:45

标签: django django-admin

假设我有一个模型,其中ID为1的行是特殊的,不应该被删除,但所有其他行都可以删除。以下是我尝试实现该逻辑:

models.py

from django.db import models


class Widget(models.Model):
    name = models.CharField(max_length=255)

    class Meta:
        ordering = ('name',)

    def __unicode__(self):
        return self.name

admin.py

from django.contrib import admin

from .models import Widget


class WidgetAdmin(admin.ModelAdmin):
    def has_delete_permission(self, request, obj=None):
        return obj is None or obj.pk != 1

admin.site.register(Widget, WidgetAdmin)

上述代码会在obj.pk1时从更改表单中删除“删除”按钮,这正是我想要的。但是,在更改列表中,如果我选中ID为1的行的复选框,然后使用“删除所选小部件”操作,我可以删除该行。我想阻止它,但仍然允许使用“删除所选小部件”操作删除所有其他行。我怎么能这样做?

2 个答案:

答案 0 :(得分:11)

根据has_delete_permission's docstring

def has_delete_permission(self, request, obj=None):
    """
    Returns True if the given request has permission to change the given
    Django model instance, ...
    """

这意味着每个请求执行has_delete_permission,而不是每个对象。在批量操作中,未设置obj。但是,您可以检查request

def has_delete_permission(self, request, obj=None):
    if request.POST and request.POST.get('action') == 'delete_selected':
        return '1' not in request.POST.getlist('_selected_action')
    return obj is None or obj.pk != 1

请注意,上述方法有效,因为the delete_selected action takes has_delete_permission into account

您可能还想提供有关错误的一些详细信息:

from django.contrib import messages

def has_delete_permission(self, request, obj=None):
    if request.POST and request.POST.get('action') == 'delete_selected':
        if '1' in request.POST.getlist('_selected_action'):
            messages.add_message(request, messages.ERROR, (
                "Widget #1 is protected, please remove it from your selection "
                "and try again."
            ))
            return False
        return True
    return obj is None or obj.pk != 1

我猜每个请求调用has_delete_permission而不是每个对象出于性能原因调用SELECT。在一般情况下,在运行has_delete_permission查询之前进行DELETE查询并循环protected function getConfigFormValues() { return array( 'HREFLANGFORPRESTASHOP_MULTISHOP_LANGUAGE_MODE' => Configuration::get('HREFLANGFORPRESTASHOP_MULTISHOP_LANGUAGE_MODE') ); } (根据其工作可能会耗费时间)是没用的。如果与此相关,则由开发人员采取必要的步骤。

答案 1 :(得分:9)

您可以使用自己的delete_selected操作取代管理员的from django.contrib.admin import actions class WidgetAdmin(admin.ModelAdmin): actions = [delete_selected] def delete_selected(self, request, queryset): # Handle this however you like. You could raise PermissionDenied, # or just remove it, and / or use the messages framework... queryset = queryset.exclude(pk=1) actions.delete_selected(self, request, queryset) delete_selected.short_description = "Delete stuff" 操作实施。类似的东西:

(function() {
    angular.module('WizmoApp').controller('StoreController', storeController);
    storeController.$inject = ['$scope', '$http', '$q', '$window', 'MyService', 'toastr'];
    function storeController($scope, $http, $q, $window, MyService, toastr) {

    StoreService.getStores().then(
        function(response) {
            console.log(response);
        },
        function(response) {
            toastr.error(response);
        });
    }
})();

有关详细信息,请参阅the documentation