正确地完成这个任务需要两个步骤:
- 隐藏编辑链接,以免有人误操作进入详细页面(更改视图)。
- 修改更改视图以重定向回列表视图。
第二部分非常重要:如果您不这样做,那么人们仍然可以通过直接输入URL访问更改视图(您可能不希望如此)。这与OWASP所谓的"不安全的直接对象引用"密切相关。
作为答案的一部分,我将构建一个ReadOnlyMixin
类,该类可用于提供所有显示的功能。
隐藏编辑链接
Django 1.7使这变得非常容易:您只需将list_display_links
设置为None
即可。
class ReadOnlyMixin():
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
这些更改将会:
- 禁用“添加 项目”按钮
- 防止人们通过在URL后添加
/add
来直接添加项目
- 防止批量删除
最后,您可以通过修改actions
参数来删除“删除所选 项目”操作。
将所有内容放在一起
这是完成的mixin:
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
class ReadOnlyMixin():
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
list_display_links = None
禁用了显示链接。 - sam