Django Admin-禁用编辑并删除特定模型的“保存”按钮

Posted

技术标签:

【中文标题】Django Admin-禁用编辑并删除特定模型的“保存”按钮【英文标题】:Django Admin- disable Editing and remove "Save" buttons for a specific model 【发布时间】:2012-01-16 13:58:20 【问题描述】:

我有一个 Django 模型,我希望它是只读的。不允许添加和编辑。

我已将 ModelAdmin 中的所有字段标记为只读并覆盖 has_add_permission 为:

class SomeModelAdmin(admin.ModelAdmin):
     def has_add_permission(self, request):
        return False

有没有类似的has_edit_permission?哪些可以禁用以删除“保存”和“保存并继续”按钮?并替换为一个简单的“关闭并返回”按钮。

Django Documentation 仅提及只读字段而不提及覆盖编辑权限。

【问题讨论】:

这是***.com/questions/3068843/…的副本 另见***.com/q/49560378 【参考方案1】:

覆盖templates/admin/submit_line.html 模板并制作任何您想要的按钮。您可以将其放入templates/admin/[app_label]/[model]/submit_line.html,仅针对特定模型执行此操作。

要有条件地显示默认提交行或您的自定义提交行,请覆盖 ModelAdmin.change_view,并将布尔值添加到 extra_context

class MyModelAdmin(admin.ModelAdmin):
    ...
    def change_view(self, request, object_id, extra_context=None):
        if not request.user.is_superuser:
            extra_context = extra_context or 
            extra_context['readonly'] = True

        return super(MyModelAdmin, self).change_view(request, object_id, extra_context=extra_context)

【讨论】:

覆盖 templates/admin/[app_label]/[model]/submit_line.html 是否仍然应该与 Django 1.4 一起使用?根据docs,每个应用程序/模型只能覆盖某些模板。 也许不是。但是,add_viewchange_view 视图都将 app_label 添加到上下文中,因此您可以使用它来测试特定应用程序。改变模型需要覆盖ModelAdmin 上的这两个视图,并将module_name 添加到上下文中。 @ChrisPratt extra_context['readonly'] = True 不适用于 Django 1.4。不知何故,变量永远不会进入submit_line.html 太糟糕了 Django 1.4 不再允许 submit_line.html 在每个应用程序/模型的基础上被覆盖。 (想知道他们为什么要摆脱它?)无论如何,在submit_line.html 中,是否显示各个按钮是由不同的上下文布尔值决定的,例如show_saveshow_delete_link 等。如何在不实际覆盖模板的情况下将它们设置为隐藏/显示按钮?我已经尝试过extra_context 但这不起作用 - 似乎这仅适用于 extra 上下文,而不是更改现有的上下文变量。有什么想法吗? 您只能在每个应用程序的基础上覆盖某些模板。 submit_line.html 不是其中之一。【参考方案2】:

我遇到了同样的问题 - 最简单的方法是包含一些自定义 JS。

在你的 admin.py 文件中包含

class Media:
    js = ('/static/js/admin.js',)

然后在你的 admin.js 文件中,包含以下 JS。

(function($) 
    $(document).ready(function($) 
         $(".submit-row").hide()
    );
)(django.jQuery);

该行已消失 - 它也应该适用于所有版本的 Django。

【讨论】:

has_delete_permission 删除删除操作甚至列表页面。覆盖 change_view 不起作用。覆盖 submit_row 模板标签也会更改所有模型的按钮。【参考方案3】:

使用 Django 1.8(Python 3 语法)更新答案。

要做三件事: 1) 扩展管理员更改表单模板,添加if 以有条件地抑制提交按钮 2) 覆盖admin.ModelAdmin.change_view() 并为模板if 设置一个上下文变量以读取 3) 禁止不需要的POST 请求(来自 DOM hacking、curl/Postman)


MyProject/my_app/templates/admin/my_app/change_form.html

% extends "admin/change_form.html" %
% load admin_modify %
% block submit_buttons_top %% if my_editable %% submit_row %% endif %% endblock %
% block submit_buttons_bottom %% if my_editable %% submit_row %% endif %% endblock %

MyProject/my_app/admin.py (MyModelAdmin)

def change_view(self, request, object_id, form_url='', extra_context=None):
  obj = MyModel.objects.get(pk=object_id)
  editable = obj.get_status() == 'Active'

  if not editable and request.method == 'POST':
    return HttpResponseForbidden("Cannot change an inactive MyModel")

  more_context = 
    # set a context var telling our customized template to suppress the Save button group
    'my_editable': editable,
  
  more_context.update(extra_context or )
  return super().change_view(request, object_id, form_url, more_context)

【讨论】:

这绝对是这个问题上现有的最佳答案。为什么点赞这么少?此外,如果您的模板在自定义路径上,请在 MyModelAdmin 类中使用 template 属性。 默认情况下,Django 将检查 change_form_template admin/myapp/model/change_form.htmladmin/myapp/change_form.html 的多个位置。 如何为所有应用禁用它? (在此之后,我可以为个别应用禁用) @akashrajkn 您可以将ModelAdmin 子类化为ReadOnlyModelAdmin 并将其用于您定义的所有应用程序。在该子类上将template 定义为readonly_change_form.html 可能最干净? 另外,建议定义get_readonly_fields,使字段显示为文本,而不是表单字段;见***.com/a/7864099/2586761【参考方案4】:

我有同样的问题。我在 admin.py 中修复了它

from django.contrib.admin.templatetags.admin_modify import register, submit_row as original_submit_row

@register.inclusion_tag('admin/submit_line.html', takes_context=True)
def submit_row(context):
''' submit buttons context change '''
ctx = original_submit_row(context)
ctx.update(
    'show_save_and_add_another': context.get('show_save_and_add_another',
                                             ctx['show_save_and_add_another']),
    'show_save_and_continue': context.get('show_save_and_continue',
                                          ctx['show_save_and_continue']),
    'show_save': context.get('show_save',
                             ctx['show_save']),
    'show_delete_link': context.get('show_delete_link', ctx['show_delete_link'])
)
return ctx

在 MyModelAdmin 类中,添加如下函数

@classmethod
def has_add_permission(cls, request):
    ''' remove add and save and add another button '''
    return False

def change_view(self, request, object_id, extra_context=None):
    ''' customize add/edit form '''
    extra_context = extra_context or 
    extra_context['show_save_and_continue'] = False
    extra_context['show_save'] = False
    return super(MyModelAdmin, self).change_view(request, object_id, extra_context=extra_context)

【讨论】:

在提供的几种替代解决方案中,这个对我有用。【参考方案5】:

对于 Django 1.11:

def has_add_permission(self, request, obj=None):
    return False

def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
    extra_context = extra_context or 
    extra_context['show_save_and_continue'] = False
    extra_context['show_save'] = False
    return super(YourModelAdmin, self).changeform_view(request, object_id, extra_context=extra_context)

【讨论】:

谢谢!结合@mat_gessel的回答(我创建了一个模板,其中read_only隐藏了保存按钮),但就其本身而言,我无法在没有覆盖的情况下隐藏Django 1.9中的“保存并添加另一个”按钮模板... @ptim: ***.com/a/54202294 解释了如何在 Django show_save_and_add_another=False。它认为,对于 Django>=2.1,它更容易。【参考方案6】:

你可以试试这个包Django Admin View Permission。这个包为指定的模型添加了一个view permission 并自动处理其他的东西。

【讨论】:

【参考方案7】:

基于优秀的answer from @mat_gessel,这是我的解决方案:

主要区别在于UX'y:

使用messages 和redirect(与reversing-admin-urls)而不是HttpResponseForbidden 来防止保存 有条件地定义 get_readonly_fields 以防止显示不可保存的输入

还有:

override change_form.html 应用范围内,因为 read_only 是一种非常有用的非侵入性增强功能 定义has_delete_permission(OP 可能不需要) 测试 request.method != 'GET' 以阻止 PATCH 和朋友(不完全确定是否需要这样做,tbh)

my_app/admin.py

​​>
from django.core.urlresolvers import reverse
from django.shortcuts import redirect

from django.contrib import admin
from django.contrib import messages


class MyModelAdmin(admin.ModelAdmin):
    # let's assume two fields...
    fields = (field1, field2)

    def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
        if object_id:
            extra_context = extra_context or 
            extra_context['read_only'] = True

            if request.method != 'GET':
                messages.error(request, "Cannot edit a MyModel object")
                return redirect(
                    reverse('admin:myapp_mymodel_change', args=[object_id])
                )

        return super(MyModelAdmin, self).changeform_view(request, object_id, extra_context=extra_context)

    def has_delete_permission(self, request, obj=None):
        return False

    def get_readonly_fields(self, request, obj=None):
        if obj:
            # display all fields as text, rather than inputs
            return (field1, field2)
        else:
            return []

admin/change_form.html

% extends "admin/change_form.html" %
% load admin_modify %
# remove the save buttons if read_only is truthy #
% block submit_buttons_top %% if not read_only %% submit_row %% endif %% endblock %
% block submit_buttons_bottom %% if not read_only %% submit_row %% endif %% endblock %

(在 Django 1.9 上测试:注意:从那时起一些导入已经移动,例如 reverse

【讨论】:

【参考方案8】:

最简单的方法是禁用 ModelAdmin 类中的相应权限。例如,我有一个 Cart 模型,我希望管理员只能查看(列表和详细信息),我所做的只是将以下函数添加到 CartAdmin 类以禁用删除、更改和添加

class CartAdmin(admin.ModelAdmin):
    list_display = ['listing']

    def has_add_permission(self, request, obj=None):
        return False

    def has_change_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

has_add_permission、has_change_permission 和 has_delete_permission 这三个方法是在后台禁用添加按钮、添加表单、编辑表单和删除按钮的方法

这是在管理员中查看已禁用上述权限的记录详细信息时的示例输出

如上图所示,只有关闭按钮,并没有在表单中显示详细信息

【讨论】:

在 django 2+ 中完美运行。您还将在管理列表显示中获得一个不错的“查看”链接。 它在 Django 1.11 中有效吗?禁止 403。【参考方案9】:

这已经有一段时间了。名称是 has_add_permissionhas_change_permissionhas_delete_permission。请参阅django admin documentation 以供参考。这里也是一个例子:

@admin.register(Object)
class Admin(admin.ModelAdmin):

    def has_add_permission(self, request):
        return False

    def has_change_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

【讨论】:

以上是关于Django Admin-禁用编辑并删除特定模型的“保存”按钮的主要内容,如果未能解决你的问题,请参考以下文章

Django admin禁用编辑链接和添加删除操作

Django Admin - 特定用户(管理员)内容

只读模型并在django admin中显示为列表?

Django Admin Cookbook-20如何删除模型的“添加”/“删除”按钮

如何使用列表中显示的相关项目的下拉列表使特定模型类的 Django contrib Admin 更改列表可编辑?

如何禁用编辑和删除rails_admin?