整个模型为只读

时间:2011-10-27 18:13:16

标签: django django-models django-admin readonly

有没有办法在django admin中创建只读模型?但我的意思是整个模型。 那么,没有添加,没有删除,没有变化,只看到对象和字段,一切都是只读的?

6 个答案:

答案 0 :(得分:11)

ModelAdmin提供了钩子get_readonly_fields() - 以下是未经测试的,我的想法是以ModelAdmin的方式确定所有字段,而不用自己的readonly字段进行递归:

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

P.S。:在ModelAdmin中,如果has_change_permission(查找或您的覆盖)返回False,则不会进入对象的更改视图 - 甚至不会显示指向它的链接。如果它确实很酷,并且默认的get_readonly_fields()检查了更改权限并在这种情况下将所有字段设置为只读,如上所述。这样非变换者至少可以浏览数据......鉴于当前的管理结构假设view = edit,正如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]
    ))

答案 1 :(得分:3)

As"查看权限"不幸的是,will not make it into Django 1.11是一个解决方案,使您的ModelAdmin 只读同时进行保存模型更改和添加模型历史记录日志条目 a no-op

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无操作助手误认为内置False。如果您不同情辅助功能在课外,将其调入课堂,称之为no_op或其他内容,或通过def s覆盖受影响的属性。减少干,但如果你不在乎......)

这将:

  1. 删除列表视图中的操作下拉框(使用"删除")
  2. 禁止添加新模型条目
  3. 禁止删除现有的模型条目
  4. 避免在模型历史记录中创建日志条目
  5. 避免显示"已成功更改"保存后的消息
  6. 避免将changeform更改保存到数据库
  7. 它不会:

    • 删除或替换两个按钮"保存并继续编辑"并且" SAVE" (这将很好地改善用户体验)

    请注意,get_all_field_names(如接受的答案中所述)为removed in Django 1.10。 用Django 1.10.5测试。

答案 2 :(得分:2)

您可以使用readonly_fields属性自定义ModelAdmin个班级。有关详情,请参阅this answer

答案 3 :(得分:1)

选择的答案不适用于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

答案 4 :(得分:0)

我有类似的情况:

  1. 用户应该能够创建模型对象
  2. 用户应该能够查看模型对象的列表
  3. 用户应该能够在创建对象后对其进行编辑
  4. 1。覆盖更改视图

    因为可以覆盖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'])
    

    2。有条件地更改编辑权限

    我也意识到文档以不同的方式解释ModelAdmin.has_change_permission()的结果:

      

    如果允许编辑obj,则返回True,否则返回False。如果   obj为None,应返回True或False以指示是否编辑   通常允许这种类型的对象(例如,False将是   解释为意味着不允许当前用户编辑   任何此类对象)。

    意思是我可以检查obj是否None,在这种情况下我返回True,否则我返回False,这实际上允许用户查看更改-list,但在保存模型实例后无法编辑或查看change_form。

    def has_change_permission(self, request, obj = None, **kwargs):
        if obj is None:
            return True
        else:
            return False
    

    虽然我认为这也可能会覆盖任何MODEL_can_change权限,允许不受欢迎的眼睛查看更改列表?

答案 5 :(得分:-1)

根据我对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]         
  ))