Django管理界面中的只读模型?

Ste*_*ett 77 django readonly django-admin

如何在管理界面中将模型完全只读?这是一种日志表,我使用管理功能进行搜索,排序,过滤等,但不需要修改日志.

如果这看起来像重复,这不是我想要做的:

  • 我不是在寻找只读字段(即使只读取每个字段仍会让你创建新记录)
  • 我不打算创建一个只读用户:每个用户都应该只读.

Dan*_*air 66

管理员用于编辑,而不仅仅是查看(您将找不到"查看"权限).为了达到你想要的效果,你必须禁止添加,删除和使所有字段只读:

class MyAdmin(ModelAdmin):

    def has_add_permission(self, request, obj=None):
        return False

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

(如果你禁止改变你甚至不会看到对象)

对于一些未经测试的代码,尝试自动设置所有字段只读,请将我对整个模型的回答看作只读

编辑:也未经测试,但只是看看我的LogEntryAdmin,它有

readonly_fields = MyModel._meta.get_all_field_names()
Run Code Online (Sandbox Code Playgroud)

不知道这是否适用于所有情况.

编辑:QuerySet.delete()仍然可以批量删除对象.要解决这个问题,请提供您自己的"对象"管理器和不删除的相应QuerySet子类 - 请参阅Django中的Overriding QuerySet.delete()

  • PS:是的,就像在另一个答案中一样,要走的路可能是在ReadOnlyAdmin类中定义这三个东西,然后从那个需要该行为的子类中继承.甚至可以得到想象并允许_are_允许编辑的组/权限的定义,然后相应地返回True(并使用有权访问请求的get_readonly_fields(),因此使用当前用户). (2认同)
  • 顺便说一句,是的readonly_fields = ...确实有效. (2认同)

dar*_*low 44

这里有两个我用来制作模型的类和/或它的内联只读.

对于模型管理员:

from django.contrib import admin

class ReadOnlyAdmin(admin.ModelAdmin):
    readonly_fields = []

    def get_readonly_fields(self, request, obj=None):
        return list(self.readonly_fields) + \
               [field.name for field in obj._meta.fields] + \
               [field.name for field in obj._meta.many_to_many]


    def has_add_permission(self, request):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

class MyModelAdmin(ReadOnlyAdmin):
    pass
Run Code Online (Sandbox Code Playgroud)

对于内联:

class ReadOnlyTabularInline(admin.TabularInline):
    extra = 0
    can_delete = False
    editable_fields = []
    readonly_fields = []
    exclude = []

    def get_readonly_fields(self, request, obj=None):
        return list(self.readonly_fields) + \
               [field.name for field in self.model._meta.fields
                if field.name not in self.editable_fields and
                   field.name not in self.exclude]

    def has_add_permission(self, request):
        return False


class MyInline(ReadOnlyTabularInline):
    pass
Run Code Online (Sandbox Code Playgroud)


Pas*_*nus 18

https://djangosnippets.org/snippets/10539/

class ReadOnlyAdminMixin(object):
    """Disables all editing capabilities."""
    change_form_template = "admin/view.html"

    def __init__(self, *args, **kwargs):
        super(ReadOnlyAdminMixin, self).__init__(*args, **kwargs)
        self.readonly_fields = self.model._meta.get_all_field_names()

    def get_actions(self, request):
        actions = super(ReadOnlyAdminMixin, self).get_actions(request)
        del_action = "delete_selected"
        if del_action in actions:
            del actions[del_action]
        return actions

    def has_add_permission(self, request):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

    def save_model(self, request, obj, form, change):
        pass

    def delete_model(self, request, obj):
        pass

    def save_related(self, request, form, formsets, change):
        pass
Run Code Online (Sandbox Code Playgroud)

模板/管理/ view.html

{% extends "admin/change_form.html" %}
{% load i18n %}

{% block submit_buttons_bottom %}
  <div class="submit-row">
    <a href="../">{% blocktrans %}Back to list{% endblocktrans %}</a>
  </div>
{% endblock %}
Run Code Online (Sandbox Code Playgroud)

templates/admin/view.html(适用于Grappelli)

{% extends "admin/change_form.html" %}
{% load i18n %}

{% block submit_buttons_bottom %}
  <footer class="grp-module grp-submit-row grp-fixed-footer">
    <header style="display:none"><h1>{% trans "submit options"|capfirst context "heading" %}</h1></header>
    <ul>
       <li><a href="../" class="grp-button grp-default">{% blocktrans %}Back to list{% endblocktrans %}</a></li>
    </ul>
  </footer>
{% endblock %}
Run Code Online (Sandbox Code Playgroud)


Jos*_*sir 12

如果您希望用户意识到他/她无法编辑它,则第一个解决方案中缺少2个.您已删除删除操作!

class MyAdmin(ModelAdmin)
    def has_add_permission(self, request, obj=None):
        return False
    def has_delete_permission(self, request, obj=None):
        return False

    def get_actions(self, request):
        actions = super(MyAdmin, self).get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions
Run Code Online (Sandbox Code Playgroud)

第二:只读解决方案在普通模型上运行良好.但它不是,如果你有外键继承的模型工作.不幸的是,我还不知道解决方案.一个很好的尝试是:

整个模型为只读

但它对我也不起作用.

最后要注意的是,如果你想考虑一个广泛的解决方案,你必须强制执行每个内联也必须是只读的.


小智 9

实际上你可以尝试这个简单的解决方案:

class ReadOnlyModelAdmin(admin.ModelAdmin):
    actions = None
    list_display_links = None
    # more stuff here

    def has_add_permission(self, request):
        return False
Run Code Online (Sandbox Code Playgroud)
  • actions = None:避免使用"删除所选..."选项显示下拉列表
  • list_display_links = None:避免单击列以编辑该对象
  • has_add_permission() 返回False可避免为该模型创建新对象


grr*_*rrr 7

它已添加到18年8月1日发行的Django 2.1中!

ModelAdmin.has_view_permission()就像现有的has_delete_permission,has_change_permission和has_add_permission一样。您可以在这里的文档中阅读

从发行说明中:

这允许授予用户对管理员中模型的只读访问权限。ModelAdmin.has_view_permission()是新的。该实现是向后兼容的,因为无需分配“查看”权限即可允许具有“更改”权限的用户编辑对象。


小智 7

使用 django 2.2+,只读管理员可以很简单:

class ReadOnlyAdminMixin:
    def has_add_permission(self, request):
        return False

    def has_change_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False


class LogEntryAdmin(ReadOnlyAdminMixin, admin.ModelAdmin):
    list_display = ('id', 'user', 'action_flag', 'content_type', 'object_repr')
Run Code Online (Sandbox Code Playgroud)


Mar*_*ian 6

编译 @darklow 和 @josir 的优秀答案,再加上添加更多内容以删除“保存”和“保存并继续”按钮导致(在 Python 3 语法中):

class ReadOnlyAdmin(admin.ModelAdmin):
    """Provides a read-only view of a model in Django admin."""
    readonly_fields = []

    def change_view(self, request, object_id, extra_context=None):
        """ customize add/edit form to remove save / save and continue """
        extra_context = extra_context or {}
        extra_context['show_save_and_continue'] = False
        extra_context['show_save'] = False
        return super().change_view(request, object_id, extra_context=extra_context)

    def get_actions(self, request):
        actions = super().get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

    def get_readonly_fields(self, request, obj=None):
        return list(self.readonly_fields) + \
           [field.name for field in obj._meta.fields] + \
           [field.name for field in obj._meta.many_to_many]

    def has_add_permission(self, request):
        return False

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

然后你使用像

class MyModelAdmin(ReadOnlyAdmin):
    pass
Run Code Online (Sandbox Code Playgroud)

我只在 Django 1.11/Python 3 上试过这个。


小智 5

如果接受的答案对您不起作用,请尝试以下操作:

def get_readonly_fields(self, request, obj=None):
    readonly_fields = []
    for field in self.model._meta.fields:
        readonly_fields.append(field.name)

    return readonly_fields
Run Code Online (Sandbox Code Playgroud)