Django管理页面,如何隐藏一个模型?

104
在注册模型出现的管理站点根页面,我想要隐藏几个已注册到Django管理站点的模型。
如果直接注销这些模型,我将无法添加新记录,因为“+”新增符号会消失。
如何完成此操作?
9个回答

140

根据x0nix的回答,我进行了一些实验。似乎从get_model_perms返回一个空字典会将该模型从index.html中排除,但仍允许直接编辑实例。

class MyModelAdmin(admin.ModelAdmin):
    def get_model_perms(self, request):
        """
        Return empty perms dict thus hiding the model from admin index.
        """
        return {}

admin.site.register(MyModel, MyModelAdmin)

同意。只是当我不想改变代码时,这就成了一个问题。我的意思是,我有一个基础应用程序,我希望保持它不依赖其他应用程序。我将这些依赖项保存在派生的项目特定应用程序中。现在,我希望管理界面仅显示派生应用程序,而不是基础应用程序。Django要求在设置/INSTALLED_APPS中列出基础应用程序才能使派生应用程序正常工作。显然,基础应用程序不应该显示,但同时我也不想让它保持未修改和可重用。请参见此处 - Sven
7
简化方式:get_model_perms = lambda self, req: {}翻译:定义一个lambda函数,使其返回空字典,函数名为get_model_perms,参数为self和req。 - Tigran Saluev
3
如果我想要隐藏一个模型对某个UserAdmin不可见,该怎么做? - Alireza Sanaee
4
请注意这个解决方案——即使链接消失了,用户仍然可以像这样跳转到对象本身:/admin/main/comment/2333/change/。 - goodgrief

51

适用于Django 1.8及以上版本

自Django 1.8版本开始,ModelAdmin类中新增了一个名为has_module_permission()的方法,负责在管理界面中显示模型。

要把一个模型从管理界面中隐藏,只需在你的ModelAdmin类中创建这个方法并返回False。例如:

class MyModelAdmin(admin.ModelAdmin):
    ...
    def has_module_permission(self, request):
        return False

不幸的是,has_module_permission 影响整个应用程序而不仅仅是一个模型。因此,在应用程序中添加此内容会导致应用程序模型列表(/admin/app_label/)中出现 403 Forbidden 错误。请参见 django/contrib/admin/sites.py - Fabian
1
@Fabian 我认为这是一个bug。我在Django的IRC频道上问过这个问题,一些人也同意这种行为是不希望出现的。 - xyres
@Fabian 假设管理员索引页面仍然链接到 _/admin/_,可以通过类似 return request.path!='/admin/' 的方式规避该错误。不幸的是,这会重新启用应用程序模型列表中的那些模型。 - ecp
我曾在这里开了一个来报告这个错误。现在已经在这里修复了。希望它能够在下一个版本中被包含进去。 - xyres
在Django 1.11中,深层链接仍然有效,但实体不会显示在主要管理屏幕上。 - Csaba Toth
1
仍在使用Django 4.0.5进行开发! - Ramon K.

24

我遇到了同样的问题,这是我的解决方法。

和之前的解决方案一样 - 从Django中复制index.html到/admin/index.html并进行修改,如下所示:

{% for model in app.models %}
    {% if not model.perms.list_hide %}
    <tr>
    ...
    </tr>
    {% endif %}
{% endfor %}

创建一个ModelAdmin子类:

class HiddenModelAdmin(admin.ModelAdmin):
    def get_model_perms(self, *args, **kwargs):
        perms = admin.ModelAdmin.get_model_perms(self, *args, **kwargs)
        perms['list_hide'] = True
        return perms

现在,任何以HiddenModelAdmin为子类注册的模型都不会出现在管理员列表中,但可以通过细节页面上的“加号”符号访问:

class MyModelAdmin(HiddenModelAdmin):
    ...

admin.site.register(MyModel, MyModelAdmin)

这个还是有效的,只是我不得不编辑app_list.html,因为我之前的索引没有包含循环部分。 另外,你可以添加一些JavaScript代码,在list_hide后如果列表为空就隐藏空的应用标题。 - d6bels
这个还是有效的,只是我不得不编辑app_list.html,因为我之前的索引没有循环内部。 另外,你可以添加一点JavaScript代码,如果列表在list_hide之后为空,就隐藏空的应用标题。 - undefined

3

截至Django 1.8.18has_module_permission()仍有问题。因此,在我们的情况下,我们还使用了get_model_perms()。同样地,我们需要仅为特定用户隐藏模型,但superuser应该能够访问其索引条目。

class MyModelAdmin(admin.ModelAdmin):
    def get_model_perms(self, request):
        if not request.user.is_superuser:
            return {}
        return super(MyModelAdmin, self).get_model_perms(request)

admin.site.register(MyModel, MyModelAdmin)

1
这是在x0nix的回答基础上的另一种构建方式,仅适用于您乐意使用jquery隐藏行的情况。
从其他回答中复制粘贴我重用的部分。
class HiddenModelAdmin(admin.ModelAdmin):
def get_model_perms(self, *args, **kwargs):
    perms = admin.ModelAdmin.get_model_perms(self, *args, **kwargs)
    perms['list_hide'] = True
    return perms

class MyModelAdmin(HiddenModelAdmin):
...

admin.site.register(MyModel, MyModelAdmin)

然后安装 django-jquery,并将以下代码块添加到您的/admin/index.html模板中:

{% extends "admin:admin/index.html" %}

{% block extrahead %}
    <script type="text/javascript" src="{{ STATIC_URL }}js/jquery.js"></script>
    {% if app_list %}
      <script type="text/javascript">
        $(function(){
          {% for app in app_list %}
            {% for model in app.models %}
                {% if model.perms.list_hide %}
                    $('div.app-{{ app.app_label }}').find('tr.model-{{ model.object_name|lower }}').hide();
                {% endif %}
            {% endfor %}
          {% endfor %}
        });
     </script>
   {% endif %}
{% endblock %}

你不需要复制整个模板,只需扩展并覆盖extrahead块。为了使上述内容起作用,你需要django-apptemplates

1

丑陋的解决方案:覆盖管理索引模板,即将django中的index.html复制到您的/admin/index.html中,并添加类似于以下内容:

{% for for model in app.models %}
    {% ifnotequal model.name "NameOfModelToHide" %}
    ...

1
只是不要在admin.py中放置admin.site.register(MyModel, MyModelAdmin)。正常注册模型即可。

1

我需要注册和隐藏很多模型管理员,如果你想要更DRY的解决方案,这个对我有用(Django 1.10,Python 3.5)

# admin.py

def register_hidden_models(*model_names):
    for m in model_names:
        ma = type(
            str(m)+'Admin',
            (admin.ModelAdmin,),
            {
                'get_model_perms': lambda self, request: {}
            })
        admin.site.register(m, ma)

register_hidden_models(MyModel1, MyModel2, MyModel3)

我想如果你想在多个应用程序中重复使用它,可以将其转换为一个实用类。

0

Django 1.2有新的if语句,这意味着只能通过覆盖admin/index.html来获得所需的功能。

{% if model.name not in "Name of hidden model; Name of other hidden model" %}
    ...
{% endif %}

这是一个糟糕的解决方案,因为它不考虑多语言管理员。当然,您可以在所有支持的语言中添加模型名称。这是一个好的解决方案,因为它不会覆盖核心Django函数的多个方面。

但在更改任何内容之前,我认为人们应该考虑一下...

本质上,问题与拥有不希望用于仅在偶尔向下拉菜单添加选项的模型有关。可以通过为“不太高级”的用户创建一组权限来有效地解决这个问题,这些用户在存在过多模型时会感到恐慌。如果需要更改特定模型,则可以使用“高级账户”登录。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接