如何在管理界面中将模型完全设为只读?它用于一种日志表,我在其中使用管理功能来搜索,排序,过滤等,但无需修改日志。
万一这看起来像是重复的,这不是我想要做的:
- 我不是在寻找只读字段(即使将每个字段都设为只读也可以让您创建新记录)
- 我不是要创建一个只读用户:每个用户都应该是只读的。
如何在管理界面中将模型完全设为只读?它用于一种日志表,我在其中使用管理功能来搜索,排序,过滤等,但无需修改日志。
万一这看起来像是重复的,这不是我想要做的:
has_view_permission
最终在Django 2.1中实现。另请参阅下面的stackoverflow.com/a/51641149。
Answers:
参见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
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 %}
Model
,或为ModelAdmin
?
ModelAdmin
。
管理员用于编辑,而不仅仅是查看(您不会找到“查看”权限)。为了实现您想要的功能,您必须禁止添加,删除所有字段并将其设置为只读:
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的回答为只读
编辑:也未经测试,但只是看看我的LogEntryAdmin,它具有
readonly_fields = MyModel._meta.get_all_field_names()
不知道这是否在所有情况下都有效。
编辑:QuerySet.delete()可能仍会批量删除对象。要解决此问题,请提供您自己的“对象”管理器以及不会删除的相应QuerySet子类-请参见在Django中覆盖QuerySet.delete()
这是我用来制作模型的两个类,并且/或者它是内联的,只读的。
对于模型管理员:
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
has_add_permission
inReadOnlyAdmin
仅接受请求作为参数
如果您希望用户知道他/她无法对其进行编辑,则第一个解决方案将缺少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
第二:只读解决方案在普通模型上运行良好。但它不是,如果你有外键继承的模型工作。不幸的是,我还不知道解决方案。一个很好的尝试是:
但这对我也不起作用。
最后一点,如果您想考虑一个广泛的解决方案,则必须强制每个内联也必须是只读的。
实际上,您可以尝试以下简单的解决方案:
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避免为该模型创建新对象它已添加到18/1/18发布的Django 2.1中!
ModelAdmin.has_view_permission()
就像现有的has_delete_permission,has_change_permission和has_add_permission一样。您可以在这里的文档中阅读
从发行说明中:
这允许授予用户对管理员中模型的只读访问权限。ModelAdmin.has_view_permission()是新的。该实现是向后兼容的,因为无需分配“查看”权限即可允许具有“更改”权限的用户编辑对象。
编译@darklow和@josir的出色答案,再加上一些内容以删除“ Save”和“ Save and Continue”按钮,将导致(使用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
然后你用像
class MyModelAdmin(ReadOnlyAdmin):
pass
我只在Django 1.11 / Python 3中尝试过此操作。
可接受的答案应该起作用,但这也将保留只读字段的显示顺序。您也不必使用此解决方案对模型进行硬编码。
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
在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
readonly_fields
和actions
行
使用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')
我已经编写了一个通用类来根据用户权限(包括内联;)处理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, ... )