Django Admin:has_delete_permission忽略为“ Delete”;行动 [英] Django Admin: has_delete_permission Ignored for "Delete" Action

查看:453
本文介绍了Django Admin:has_delete_permission忽略为“ Delete”;行动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Let's say that I have a model where the row that has an ID of 1 is special and should not be able to be deleted, but all the other rows are fine to delete. Here is my attempt at implementing that logic:

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



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.pk 1 ,这就是我想要的。但是,在更改列表上,如果我选中ID为1的行的复选框,然后使用删除选定的小部件操作,则可以删除该行。我想避免这种情况,但仍然允许通过删除选定的小部件操作删除所有其他行。我该怎么做?

The above code removes the "Delete" button from the change form when obj.pk is 1, which is what I want. However, on the change list, if I check the checkbox for the row with an ID of 1 and then use the "Delete selected widgets" action, I am able to delete that row. I want to prevent that, but still allow all of the other rows to be deleted with the "Delete selected widgets" action. How can I do this?

推荐答案

根据 has_delete_permission 的文档字符串

According to 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 。但是,您可以检查请求

This means has_delete_permission is executed per request, not per object. On a bulk action, obj is not set. However you may examine 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

请注意,上述方法有效是因为 delete_selected 操作考虑 has_delete_permission

Note that the above works because the delete_selected action takes has_delete_permission into account.

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

You may also want to provide some details about the error:

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

我猜<$出于性能原因,每个请求而不是每个对象都调用c $ c> has_delete_permission 。在一般情况下,进行 SELECT 查询并循环遍历 has_delete_permission 是没有用的(根据(它的作用)),然后再运行 DELETE 查询。并且在需要这样做时,由开发人员来采取必要的步骤。

I guess has_delete_permission is called per request rather than per object for performance reasons. In the general case, it is useless to make a SELECT query and loop over has_delete_permission (which may be time consuming according to what it does) prior to running the DELETE query. And when it's relevant to do so, it's up to the developer to take the necessary steps.

这篇关于Django Admin:has_delete_permission忽略为“ Delete”;行动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆