正确执行此操作需要两个步骤:
- 隐藏编辑链接,所以没有人会错误地发现详细信息页面(更改视图)。
- 修改更改视图以重定向回列表视图。
第二部分很重要:如果您不这样做,那么人们仍然可以通过直接输入 URL 来访问更改视图(这可能是您不想要的)。这与 OWASP 术语“不安全的直接对象引用”密切相关。
作为此答案的一部分,我将构建一个ReadOnlyMixin
可用于提供显示的所有功能的类。
隐藏编辑链接
Django 1.7 使这变得非常简单:您只需list_display_links
将None
.
class ReadOnlyMixin(): # Add inheritance from "object" if using Python 2
list_display_links = None
Django 1.6(可能更早)并没有让这变得如此简单。这个问题的很多答案都建议重写__init__
以便list_display_links
在构造对象后设置,但这使得重用变得更加困难(我们只能重写构造函数一次)。
我认为更好的选择是覆盖 Django 的get_list_display_links
方法,如下所示:
def get_list_display_links(self, request, list_display):
"""
Return a sequence containing the fields to be displayed as links
on the changelist. The list_display parameter is the list of fields
returned by get_list_display().
We override Django's default implementation to specify no links unless
these are explicitly set.
"""
if self.list_display_links or not list_display:
return self.list_display_links
else:
return (None,)
这使我们的 mixin 易于使用:默认情况下它隐藏了编辑链接,但允许我们在特定管理视图需要时将其添加回来。
重定向到列表视图
change_view
我们可以通过重写该方法来更改详细信息页面的行为(更改视图) 。这是 Chris Pratt 建议的技术的扩展,它会自动找到正确的页面:
enable_change_view = False
def change_view(self, request, object_id, form_url='', extra_context=None):
"""
The 'change' admin view for this model.
We override this to redirect back to the changelist unless the view is
specifically enabled by the "enable_change_view" property.
"""
if self.enable_change_view:
return super(ReportMixin, self).change_view(
request,
object_id,
form_url,
extra_context
)
else:
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
opts = self.model._meta
url = reverse('admin:{app}_{model}_changelist'.format(
app=opts.app_label,
model=opts.model_name,
))
return HttpResponseRedirect(url)
同样,这是可自定义的 - 通过切换enable_change_view
到True
您可以重新打开详细信息页面。
删除“添加项目”按钮
最后,您可能希望覆盖以下方法以防止人们添加或删除新项目。
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return False
这些变化将:
- 禁用“添加项目”按钮
/add
通过附加到 URL 来防止人们直接添加项目
- 防止批量删除
最后,您可以通过修改参数来删除“删除选定项目”操作。actions
把它们放在一起
这是完成的mixin:
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
class ReadOnlyMixin(): # Add inheritance from "object" if using Python 2
actions = None
enable_change_view = False
def get_list_display_links(self, request, list_display):
"""
Return a sequence containing the fields to be displayed as links
on the changelist. The list_display parameter is the list of fields
returned by get_list_display().
We override Django's default implementation to specify no links unless
these are explicitly set.
"""
if self.list_display_links or not list_display:
return self.list_display_links
else:
return (None,)
def change_view(self, request, object_id, form_url='', extra_context=None):
"""
The 'change' admin view for this model.
We override this to redirect back to the changelist unless the view is
specifically enabled by the "enable_change_view" property.
"""
if self.enable_change_view:
return super(ReportMixin, self).change_view(
request,
object_id,
form_url,
extra_context
)
else:
opts = self.model._meta
url = reverse('admin:{app}_{model}_changelist'.format(
app=opts.app_label,
model=opts.model_name,
))
return HttpResponseRedirect(url)
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return False