如何在管理界面中将模型完全只读?这是一种日志表,我使用管理功能进行搜索,排序,过滤等,但不需要修改日志。
如果这看起来像重复,这里的不是我正在尝试做的事情:
答案 0 :(得分:65)
管理员用于编辑,而不仅仅是查看(您将找不到“查看”权限)。为了达到你想要的效果,你必须禁止添加,删除和使所有字段只读:
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
答案 1 :(得分:41)
以下是我用来制作模型和/或内联只读的两个类。
对于模特管理员:
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
答案 2 :(得分:15)
请参阅https://djangosnippets.org/snippets/10539/
df = df.rename(columns={col: col.split('_')[0] for col in df.columns})
<强>模板/管理/ view.html 强>
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 actions["delete_selected"]
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(适用于Grappelli)
{% 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 %}
答案 3 :(得分: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
第二:只读解决方案在普通模型上运行良好。但是如果你有一个带有外键的继承模型,它确实 NOT 工作。不幸的是,我还不知道解决方案。一个很好的尝试是:
但它对我也不起作用。
最后一点,如果你想考虑一个广泛的解决方案,你必须强制执行每个内联也必须是只读。
答案 4 :(得分: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可避免为该模型创建新对象答案 5 :(得分:4)
如果接受的答案对您不起作用,请尝试以下方法:
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
答案 6 :(得分:4)
编译@darklow和@josir的优秀答案,再添加一些内容以删除&#34; Save&#34;和&#34;保存并继续&#34;按钮导致(在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尝试过这个。
答案 7 :(得分:4)
此功能已添加到Django 2.1中,该版本于8/1/18发布!
ModelAdmin.has_view_permission()
就像现有的has_delete_permission,has_change_permission和has_add_permission一样。您可以在文档here
摘自发行说明:
这允许用户以只读方式访问管理员中的模型。 ModelAdmin.has_view_permission()是新的。实现是 向后兼容,因为不需要分配“视图” 允许具有“更改”权限的用户进行编辑的权限 对象。
答案 8 :(得分:3)
在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
答案 9 :(得分:2)
接受的答案应该有效,但这也将保留只读字段的显示顺序。您也不必使用此解决方案对模型进行硬编码。
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
答案 10 :(得分:1)
当需要为django管理员中的某些用户准备所有字段时,我遇到了相同的要求,最终利用django模块“django-admin-view-permission”而没有滚动我自己的代码。如果您需要更精细的控制来明确定义哪些字段,那么您需要扩展模块。您可以查看操作中的插件here
答案 11 :(得分:1)
使用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')
答案 12 :(得分:0)
pipenv install django-admin-view-permission
6666
答案 13 :(得分:0)
我编写了一个通用类来处理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, ... )