正确执行此操作需要两个步骤:
- 隐藏编辑链接,这样没有人会误入详细信息页面(更改视图)。
- 修改更改视图以重定向回列表视图。
第二部分很重要:如果您不这样做,那么人们仍然可以通过直接输入 URL 来访问更改视图(这可能是您不想要的)。这与 OWASP 术语 "Insecure Direct Object Reference" 密切相关。
作为此答案的一部分,我将构建一个 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,您可以重新打开详细信息页面。
删除“添加ITEM”按钮
最后,您可能希望覆盖以下方法以防止人们添加或删除新项目。
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