在Django的管理员中,我希望禁用“选择要更改的项目”页面上提供的链接,以便用户无法去任何地方编辑项目。 (我将限制用户可以对此列表执行的操作到一组下拉操作 - 没有实际编辑字段。)
我看到Django有choose which fields display the link的能力,但是,我看不出我怎么能拥有 none 。
class HitAdmin(admin.ModelAdmin):
list_display = ('user','ip','user_agent','hitcount')
search_fields = ('ip','user_agent')
date_hierarchy = 'created'
list_display_links = [] # doesn't work, goes to default
如何获取我的对象列表而没有任何编辑链接?
答案 0 :(得分:59)
我只想将日志查看器作为列表。
我得到了这样的工作:
class LogEntryAdmin(ModelAdmin):
actions = None
list_display = (
'action_time', 'user',
'content_type', 'object_repr',
'change_message')
search_fields = ['=user__username', ]
fieldsets = [
(None, {'fields':()}),
]
def __init__(self, *args, **kwargs):
super(LogEntryAdmin, self).__init__(*args, **kwargs)
self.list_display_links = (None, )
这是两种答案之间的混合。
如果您只是self.list_display_links = ()
,它会显示链接,无论如何,因为template-tag
代码(templatetags / admin_list.py)再次检查该列表是否为空。
答案 1 :(得分:30)
正确执行此操作需要两个步骤:
第二部分很重要:如果你不这样做,那么人们仍然可以通过直接输入网址来访问更改视图(这可能是你不想要的)。这与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
,但是这使得重用更加困难(我们只能覆盖构造函数一次)。 / p>
我认为更好的选择是覆盖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
附加到网址最后,您可以删除"删除所选的项目"通过修改actions
参数来执行操作。
这是完成的混音:
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
答案 2 :(得分:18)
作为上述评论中提到的用户,omat,任何只是删除链接的尝试都不会阻止用户仍然手动访问更改页面。但是,这也很容易补救:
class MyModelAdmin(admin.ModelAdmin)
# Other stuff here
def change_view(self, request, obj=None):
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
return HttpResponseRedirect(reverse('admin:myapp_mymodel_changelist'))
答案 3 :(得分:11)
在Django 1.7及更高版本中,你可以做到
class HitAdmin(admin.ModelAdmin):
list_display_links = None
答案 4 :(得分:7)
答案 5 :(得分:2)
没有受支持的方式来执行此操作。
查看代码,如果您没有将其设置为任何内容,它似乎会自动将ModelAdmin.list_display_links
设置为第一个元素。因此,最简单的方法可能是覆盖__init__
子类中的ModelAdmin
方法,以便在初始化时取消设置该属性:
class HitAdmin(admin.ModelAdmin):
list_display = ('user','ip','user_agent','hitcount')
search_fields = ('ip','user_agent')
date_hierarchy = 'created'
def __init__(self, *args, **kwargs):
super(HitAdmin, self).__init__(*args, **kwargs)
self.list_display_links = []
经过粗略的测试后,这似乎有效。我不能保证它不会在其他地方破坏任何东西,或者不会因为Django的未来变化而破坏它。
评论后修改:
无需修补源代码,这可行:
def __init__(self, *args, **kwargs):
if self.list_display_links:
unset_list_display = True
else:
unset_list_display = False
super(HitAdmin, self).__init__(*args, **kwargs)
if unset_list_display:
self.list_display_links = []
但是我非常怀疑Django会接受任何补丁,因为这会破坏代码目前明确做的事情。
答案 6 :(得分:2)
仅为备注,您可以修改changelist_view:
class SomeAdmin(admin.ModelAdmin):
def changelist_view(self, request, extra_context=None):
self.list_display_links = (None, )
return super(SomeAdmin, self).changelist_view(request, extra_context=None)
这对我来说很好。
答案 7 :(得分:1)
你也可能 荒谬 hacky(如果你不想对重写init
大惊小怪)并为第一个元素提供一个值基本上看起来像这样:
</a>My non-linked value<a>
我知道,我知道,不是很漂亮,但也许不会因为我们正在做的事情正在改变标记而在其他地方打破某些事情。
以下是一些有关其工作原理的示例代码:
class HitAdmin(admin.ModelAdmin):
list_display = ('user_no_link','ip','user_agent','hitcount')
def user_no_link(self, obj):
return u'</a>%s<a>' % obj
user_no_link.allow_tags = True
user_no_link.short_description = "user"
附注:您还可以通过返回return u'%s' % obj.get_full_name()
来提高输出的可读性(因为您不希望它成为链接),这可能是有点整洁,具体取决于您的用例。
答案 8 :(得分:1)
使用django 1.6.2你可以这样做:
class MyAdmin(admin.ModelAdmin):
def get_list_display_links(self, request, list_display):
return []
它会隐藏所有自动生成的链接。
答案 9 :(得分:1)
只需在管理员中写入sdk-1.38.28-64bit
答案 10 :(得分:1)
在Django的“最新”版本中,至少从1.9开始,可以简单地确定admin类的添加,更改和删除权限。请参阅django admin documentation以供参考。这是一个示例:
let newArray = lodash.uniqBy(lodash.concat(myArray, 'subdata.subid'), '_id');
答案 11 :(得分:0)
我将get_list_display_links方法和操作覆盖为无。
class ChangeLogAdmin(admin.ModelAdmin):
actions = None
list_display = ('asset', 'field', 'before_value', 'after_value', 'operator', 'made_at')
fieldsets = [
(None, {'fields': ()}),
]
def __init__(self, model, admin_site):
super().__init__(model, admin_site)
def get_list_display_links(self, request, list_display):
super().get_list_display_links(request, list_display)
return None