在Django管理界面中,有没有一种方法可以使整个模型只读?我是指整个模型。 因此,不允许添加、删除或更改任何内容,只能查看对象和字段,所有操作都只读?
在Django管理界面中,有没有一种方法可以使整个模型只读?我是指整个模型。 因此,不允许添加、删除或更改任何内容,只能查看对象和字段,所有操作都只读?
ModelAdmin 提供了 get_readonly_fields() 方法 - 下面的代码未经测试,我的想法是像 ModelAdmin 一样确定所有字段,而不会遇到只读字段本身的递归问题:
from django.contrib.admin.util import flatten_fieldsets
class ReadOnlyAdmin(ModelAdmin):
def get_readonly_fields(self, request, obj=None):
if self.declared_fieldsets:
fields = flatten_fieldsets(self.declared_fieldsets)
else:
form = self.get_formset(request, obj).form
fields = form.base_fields.keys()
return fields
然后在需要只读管理员的地方,创建该管理员的子类或Mixin。
对于添加/删除操作,为了使它们的按钮消失,您可能还需要添加:
def has_add_permission(self, request):
# Nobody is allowed to add
return False
def has_delete_permission(self, request, obj=None):
# Nobody is allowed to delete
return False
顺便提一下,在 ModelAdmin 中,如果 has_change_permission(查询或您的覆盖)返回 False,则无法访问对象的更改视图 - 连接也不会显示。如果实际上可以这样做,并且默认的 get_readonly_fields()检查更改权限并在这种情况下将所有字段设置为只读,那将非常棒,这样非更改者即使只能浏览数据...鉴于当前的管理结构假定视图=编辑,正如 jathanism 指出的那样,这可能需要引入一个“查看”权限来覆盖添加/更改/删除...
编辑:关于设置所有字段为只读,虽然未经测试,但看起来很有希望:
readonly_fields = MyModel._meta.get_all_field_names()
编辑:这里还有另一个
if self.declared_fieldsets:
return flatten_fieldsets(self.declared_fieldsets)
else:
return list(set(
[field.name for field in self.opts.local_fields] +
[field.name for field in self.opts.local_many_to_many]
))
_meta.get_all_field_names()
在Django 1.10中已被移除。请参考https://docs.djangoproject.com/en/1.10/ref/models/meta/#migrating-from-the-old-api 进行迁移。 - hashlash所选答案不适用于Django 1.11,我找到了一种更简单的方法来解决这个问题,所以我想分享一下:
class MyModelAdmin(admin.ModelAdmin):
def get_readonly_fields(self, request, obj=None):
return [f.name for f in obj._meta.fields]
def has_delete_permission(self, request, obj=None):
return False
def has_add_permission(self, request):
return False
def false(*args, **kwargs):
"""A simple no-op function to make our changes below readable."""
return False
class MyModelReadOnlyAdmin(admin.ModelAdmin):
list_display = [
# list your admin listview entries here (as usual)
]
readonly_fields = [
# list your read-only fields here (as usual)
]
actions = None
has_add_permission = false
has_delete_permission = false
log_change = false
message_user = false
save_model = false
(注意: 不要将false
no-op helper和False
builtin混淆。如果您不喜欢类外的helper函数,请将其移入类中,将其命名为no_op
或其他名称,或通过通常的def
覆盖受影响的属性。DRY原则会降低一些,但如果您不在意也可以这样做...)
这将:
它不会:
get_all_field_names
在Django 1.10中已经被删除。使用Django 1.10.5进行测试。我曾经遇到过类似的情况:
因为在ModelAdmin中可以覆盖change_view()
,我们可以利用这一点来防止编辑已创建的模型实例。以下是我使用的示例:
def change_view(self, request, object_id, form_url='', extra_context=None):
messages.error(request, 'Sorry, but editing is NOT ALLOWED')
return redirect(request.META['HTTP_REFERER'])
我还意识到文档对 ModelAdmin.has_change_permission()
的结果有不同的解释:
如果允许编辑 obj,则应返回 True,否则返回 False。如果 obj 为 None,则应返回 True 或 False,以指示是否一般允许编辑此类型的对象(例如,False 将被解释为当前用户无权编辑此类型的任何对象)。
这意味着我可以检查 obj
是否为 None
,在这种情况下返回 True
,否则返回 False
,这实际上允许用户查看更改列表,但不能在保存模型实例后编辑或查看更改表单。
def has_change_permission(self, request, obj = None, **kwargs):
if obj is None:
return True
else:
return False
我认为这可能也会覆盖任何MODEL_can_change
权限,允许不需要的人查看更改列表?
根据我在Django 1.8上的测试,我们不能像答案#3中所述那样使用以下内容,但它在Django 1.4上可以工作:
## self.get_formset(request, obj) ##
answer 3 needs fix. Generally, alternative codes for this issue about below section
## form = self.get_formset(request, obj).form ##
## fields = form.base_fields.keys() ##
可以是类似于这样的东西:
#~ (A) or
[f.name for f in self.model._meta.fields]
#~ (B) or
MyModel._meta.get_all_field_names()
#~ (C)
list(set([field.name for field in self.opts.local_fields] +
[field.name for field in self.opts.local_many_to_many]
))