Django管理界面中的只读模型?
Posted
技术标签:
【中文标题】Django管理界面中的只读模型?【英文标题】:Readonly models in Django admin interface? 【发布时间】:2012-01-06 02:39:41 【问题描述】:如何在管理界面中将模型设为完全只读?这是一种日志表,我使用管理功能进行搜索、排序、过滤等,但不需要修改日志。
如果这看起来像重复,这是我想要做的不是:
我不是在寻找只读字段(即使将每个字段设为只读仍然可以让您创建新记录) 我不打算创建只读用户:每个用户都应该是只读的。【问题讨论】:
此功能即将推出:github.com/django/django/pull/5297has_view_permission
终于在 Django 2.1 中实现了。另请参阅下面的***.com/a/51641149。
【参考方案1】:
管理员用于编辑,而不仅仅是查看(您不会找到“查看”权限)。为了实现您想要的,您必须禁止添加、删除和将所有字段设为只读:
class MyAdmin(ModelAdmin):
def has_add_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False
(如果你禁止更改,你甚至不会看到对象)
对于一些试图自动将所有字段设置为只读的未经测试的代码,请参阅我对Whole model as read-only的回答
编辑:也未经测试,但只是看看我的 LogEntryAdmin,它有
readonly_fields = MyModel._meta.get_all_field_names()
不知道这是否适用于所有情况。
编辑:QuerySet.delete() 仍可能批量删除对象。要解决这个问题,请提供您自己的“对象”管理器和相应的不会删除的 QuerySet 子类 - 请参阅 Overriding QuerySet.delete() in Django
【讨论】:
P.S.:是的,就像在另一个答案中一样,要走的路可能是在 ReadOnlyAdmin 类中定义这三件事,然后在您需要该行为的任何地方从该类中定义。甚至可以花哨并允许定义允许编辑的组/权限,然后相应地返回 True(并使用 get_readonly_fields() 可以访问请求并因此访问当前用户)。 几乎完美。我可以贪婪地问是否有办法不让行链接到编辑页面? (同样,无需放大任何行,也无需编辑任何内容) 如果您将 ModelAdmin 的 list_display_links 设置为评估为 False 的内容(如空列表/元组),ModelAdmin.__init__() 会将 list_display_links 设置为所有列(操作复选框除外) - 请参阅 options.py .我想这样做是为了确保有链接。所以我会在 ReadOnlyAdmin 中覆盖 __init__(),调用父级然后将 list_display_links 设置为空列表或元组。鉴于您现在没有指向只读更改表单的链接,可能最好为此创建一个参数/类属性 - 我不认为这是通常需要的行为。 Hth 关于从模型中设置的 readonly_fields,如果您覆盖表单并添加其他字段,这可能不起作用...基于 actual 表单字段可能是更好。 这不起作用:def __init__(self, *args): super(RegistrationStatusAdmin, self).__init__(*args) self.display_links=[]【参考方案2】:如果您希望用户意识到他/她无法对其进行编辑,则第一个解决方案中缺少 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
第二:只读解决方案适用于普通模型。但如果您有一个带有外键的继承模型,它确实不工作。不幸的是,我还不知道解决方案。一个好的尝试是:
Whole model as read-only
但这对我也不起作用。
最后一点,如果你想考虑一个广泛的解决方案,你必须强制每个内联也必须是只读的。
【讨论】:
【参考方案3】:如果接受的答案不适合你,试试这个:
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
【讨论】:
【参考方案4】:这是我用来制作模型和/或内联只读的两个类。
对于模型管理员:
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
对于内联:
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
【讨论】:
如何将两个类应用到一个子类。例如。如果我在课堂上有正常的字段和内联?我可以同时延期吗? @timo 使用这些类as mixinshas_add_permission
in ReadOnlyAdmin
只接受请求作为参数
has_change_permission() 也需要被覆盖。 def has_change_permission(self, request, obj=None):【参考方案5】:
接受的答案应该有效,但这也会保留只读字段的显示顺序。您也不必使用此解决方案对模型进行硬编码。
class ReadonlyAdmin(admin.ModelAdmin):
def __init__(self, model, admin_site):
super(ReadonlyAdmin, self).__init__(model, admin_site)
self.readonly_fields = [field.name for field in filter(lambda f: not f.auto_created, model._meta.fields)]
def has_delete_permission(self, request, obj=None):
return False
def has_add_permission(self, request, obj=None):
return False
【讨论】:
【参考方案6】:见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 = [f.name for f in self.model._meta.get_fields()]
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
templates/admin/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 %
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 %
【讨论】:
似乎合法。不过,我已经很久没有使用 Django 了,可能会等着看其他评论者怎么说。 这是Model
还是ModelAdmin
的mixin?
这是给ModelAdmin
的。
对于 Django 1.8 及更高版本,不推荐使用 get_all_field_names。 Backwards compatible way to get them。 Short way to get them.
你可以使用 has_add_permission【参考方案7】:
其实你可以试试这个简单的解决方案:
class ReadOnlyModelAdmin(admin.ModelAdmin):
actions = None
list_display_links = None
# more stuff here
def has_add_permission(self, request):
return False
actions = None
:避免显示带有“删除选定...”选项的下拉菜单
list_display_links = None
:避免点击列来编辑该对象
has_add_permission()
返回 False 可避免为该模型创建新对象
【讨论】:
这禁止打开任何实例来查看字段,但是如果只列出列表就可以了,那么它可以工作。【参考方案8】:当需要为 django admin 中的某些用户设置所有字段只读时,我遇到了相同的要求,最终利用 django 模块“django-admin-view-permission”而不滚动我自己的代码。如果您需要更细粒度的控制来明确定义哪些字段,那么您需要扩展模块。您可以查看正在使用的插件here
【讨论】:
【参考方案9】:编译 @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
然后你用like
class MyModelAdmin(ReadOnlyAdmin):
pass
我只在 Django 1.11 / Python 3 上试过这个。
【讨论】:
很久没用Django了。其他人可以为此担保吗? @SteveBennettㄹ 这个解决的要求有很多变化......这个答案不是水密的......在这里建议解释:@ 987654321@和你评论的答案@ 987654322@ 比接受的答案更完整【参考方案10】:只读 => 查看权限
pipenv install django-admin-view-permission
在 settings.py 中将 'admin_view_permission' 添加到 INSTALLED_APPS。如下所示:
`INSTALLED_APPS = [
'admin_view_permission',
python manage.py 迁移
python manage.py runserver 6666
ok.享受“views”权限的乐趣
【讨论】:
【参考方案11】:我编写了一个通用类来根据用户权限(包括内联)处理 ReadOnly 视图;)
在models.py中:
class User(AbstractUser):
...
def is_readonly(self):
if self.is_superuser:
return False
# make readonly all users not in "admins" group
adminGroup = Group.objects.filter(name="admins")
if adminGroup in self.groups.all():
return False
return True
在 admin.py 中:
# read-only user filter class for ModelAdmin
class ReadOnlyAdmin(admin.ModelAdmin):
def __init__(self, *args, **kwargs):
# keep initial readonly_fields defined in subclass
self._init_readonly_fields = self.readonly_fields
# keep also inline readonly_fields
for inline in self.inlines:
inline._init_readonly_fields = inline.readonly_fields
super().__init__(*args,**kwargs)
# customize change_view to disable edition to readonly_users
def change_view( self, request, object_id, form_url='', extra_context=None ):
context = extra_context or
# find whether it is readonly or not
if request.user.is_readonly():
# put all fields in readonly_field list
self.readonly_fields = [ field.name for field in self.model._meta.get_fields() if not field.auto_created ]
# readonly mode fer all inlines
for inline in self.inlines:
inline.readonly_fields = [field.name for field in inline.model._meta.get_fields() if not field.auto_created]
# remove edition buttons
self.save_on_top = False
context['show_save'] = False
context['show_save_and_continue'] = False
else:
# if not readonly user, reset initial readonly_fields
self.readonly_fields = self._init_readonly_fields
# same for inlines
for inline in self.inlines:
inline.readonly_fields = self._init_readonly_fields
return super().change_view(
request, object_id, form_url, context )
def save_model(self, request, obj, form, change):
# disable saving model for readonly users
# just in case we have a malicious user...
if request.user.is_readonly():
# si és usuari readonly no guardem canvis
return False
# if not readonly user, save model
return super().save_model( request, obj, form, change )
然后,我们就可以正常继承 admin.py 中的类了:
class ContactAdmin(ReadOnlyAdmin):
list_display = ("name","email","whatever")
readonly_fields = ("updated","created")
inlines = ( PhoneInline, ... )
【讨论】:
【参考方案12】:这是在 2018 年 8 月 1 日发布的 Django 2.1 中添加的!
ModelAdmin.has_view_permission()
就像现有的 has_delete_permission、has_change_permission 和 has_add_permission。您可以在文档here
来自发行说明:
这允许在管理员中授予用户对模型的只读访问权限。 ModelAdmin.has_view_permission() 是新的。实现是 向后兼容,因为不需要分配“视图” 允许具有“更改”权限的用户进行编辑的权限 对象。
【讨论】:
超级用户仍然可以在管理界面中修改对象,对吧? 这是正确的,除非您覆盖其中一种方法来更改行为以禁止超级用户访问。【参考方案13】:在 Django 2.2 中,我这样做:
@admin.register(MyModel)
class MyAdmin(admin.ModelAdmin):
readonly_fields = ('all', 'the', 'necessary', 'fields')
actions = None # Removes the default delete action in list view
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
【讨论】:
对于 django 2.2,readonly_fields
和 actions
行不是必需的【参考方案14】:
使用 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')
【讨论】:
这正是我想要的。谢谢~以上是关于Django管理界面中的只读模型?的主要内容,如果未能解决你的问题,请参考以下文章