在django的admin(仅显示列表)中禁用编辑对象的链接?

tho*_*mad 43 python django modeladmin django-admin

在Django的管理员中,我想禁用 "选择要更改的项目"页面上提供的链接,以便用户无法去任何地方编辑项目.(我将限制用户可以对此列表执行的操作到一组下拉操作 - 没有实际编辑字段).

我看到Django能够选择显示链接的字段,但是,我看不出我怎么也没有.

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
Run Code Online (Sandbox Code Playgroud)

任何想法如何获取我的对象列表没有任何链接编辑?

Fed*_*ico 60

我只想将日志查看器作为列表.

我得到它像这样工作:

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, )
Run Code Online (Sandbox Code Playgroud)

它是两种答案之间的混合.

如果您这样做self.list_display_links = (),它将显示链接,无论如何,因为template-tag代码(templatetags/admin_list.py)再次检查以查看列表是否为空.

  • 非答案提供了一种实际禁止更改日志条目的方法.虽然用户没有看到链接,但他可以通过在编辑表单中键入URL来访问编辑表单,并可以更改条目.用户必须具有"can_change"权限才能查看更改列表视图.这引入了一个严重的安全漏洞. (3认同)
  • 刚找到你的帖子,这也适合我(在`__init__`中设置`self.list_diplay_links =(None,)`.谢谢! (2认同)
  • @omat:您可以覆盖ModelAdmin.change_view以重定向到更改列表页面,或者如果有人尝试手动访问该页面,或者您喜欢的任何地方.我将在下面提供一个例子. (2认同)
  • 不幸的是,这在 Django 2.2 中似乎不起作用。现在 Django 给你错误“‘list_display_links[0]’的值引用‘None’,它没有在‘list_display’中定义。” (2认同)
  • @Cerin 只需使用 `list_display_links = None` (2认同)

sim*_*igh 32

正确执行此操作需要两个步骤:

  • 隐藏编辑链接,因此没有人在错误的详细信息页面(更改视图)上绊倒.
  • 修改更改视图以重定向回列表视图.

第二部分很重要:如果你不这样做,那么人们仍然可以通过直接输入URL来访问更改视图(这可能是你不想要的).这与OWASP所称的"不安全直接对象参考"密切相关.

作为这个答案的一部分,我将构建一个ReadOnlyMixin可用于提供所有功能的类.

隐藏编辑链接

Django的1.7使这真的很简单:您只需设置list_display_linksNone.

class ReadOnlyMixin(): # Add inheritance from "object" if using Python 2
    list_display_links = None
Run Code Online (Sandbox Code Playgroud)

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,)
Run Code Online (Sandbox Code Playgroud)

这使得我们的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)
Run Code Online (Sandbox Code Playgroud)

再次这是可自定义的 - 通过切换enable_change_viewTrue您可以重新打开详细信息页面.

删除"添加项目 "按钮

最后,您可能希望覆盖以下方法,以防止人们添加或删除新项目.

def has_add_permission(self, request):
    return False

def has_delete_permission(self, request, obj=None):
    return False
Run Code Online (Sandbox Code Playgroud)

这些变化将:

  • 禁用"添加项目 "按钮
  • 阻止人们通过附加/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
Run Code Online (Sandbox Code Playgroud)


Chr*_*att 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'))
Run Code Online (Sandbox Code Playgroud)


Bla*_*ise 15

在Django 1.7及更高版本中,你可以做到

class HitAdmin(admin.ModelAdmin):
    list_display_links = None
Run Code Online (Sandbox Code Playgroud)


Jos*_*man 7

在您的模型管理集中:

list_display_links = (None,)
Run Code Online (Sandbox Code Playgroud)

应该这样做.(无论如何都适用于1.1.1.)

链接到docs:list_display_links


小智 5

只需list_display_links = None在您的管理员中写入