【问题标题】:Whole model as read-only整个模型为只读
【发布时间】:2011-12-16 17:58:20
【问题描述】:

有没有办法在 django 管理员中使模型只读?但我的意思是整个模型。 所以,没有添加,没有删除,没有改变,只看到对象和字段,一切都是只读的?

【问题讨论】:

  • 这似乎是一项正在进行的工作:github.com/django/django/pull/5297
  • 注意,覆盖 has_change_permission() 将只允许添加/删除,但不能编辑现有记录(在 Django Admin 中)

标签: django django-models django-admin readonly


【解决方案1】:

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

然后子类/混合这个管理员,只要它应该是一个只读管理员。

对于添加/删除,以及使它们的按钮消失,您可能还需要添加

    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]
    ))

【讨论】:

  • PS:我现在已经创建了一个功能请求code.djangoproject.com/ticket/17295
  • 注意:get_formset 方法只为 InlineModelAdmin 定义
  • 您好,感谢您对选项的编译。可能有礼貌,但也提供您从中获得的答案的链接,因为我认为它们并不都是您的。另一个好处是读者还可以看到其他人对每条建议的看法。
  • 在 Django 1.11 中不起作用 - AttributeError: 'ReadOnlyAdmin' 对象没有属性 'declared_fieldsets'
  • _meta.get_all_field_names() 在 Django 1.10 中被删除 docs.djangoproject.com/en/1.10/ref/models/meta/…
【解决方案2】:

作为“查看权限”will not make it into Django 1.11,不幸的是,这里有一个解决方案,通过保存模型更改和添加模型历史日志条目使您的 ModelAdmin 只读

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 内置函数混淆。如果您不同意类外的帮助函数,请将其移入类,将其命名为 no_op 或其他名称,或者用通常的 defs 覆盖受影响的属性。不太干,但如果你不在乎...)

这将:

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

它不会:

  • 删除或替换“保存并继续编辑”和“保存”两个按钮(这将有助于改善用户体验)

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

【讨论】:

    【解决方案3】:

    所选答案不适用于 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】:

      您可以使用readonly_fields 属性自定义您的ModelAdmin 类。请参阅this answer 了解更多信息。

      【讨论】:

      • 但是有没有办法将整个模型设为只读,而不必将其所有属性添加到只读字段列表中?
      • 有,但不容易。您可以在 Django 中创建自定义权限,但是对于管理站点而言,这并非易事。 Django 假设如果人们被允许在管理界面中查看内容,他们也被允许编辑它。如果你觉得大胆,你可以试试this question 的建议。 IMO 将所有字段显式设置为只读并继续前进会更容易。
      【解决方案5】:

      我有一个类似的场景:

      1. 用户应该能够创建模型对象
      2. 用户应该能够查看模型对象列表
      3. 用户不应该在对象创建后对其进行编辑

      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,这实际上允许用户查看更改列表,但无法查看保存模型实例后编辑或查看 change_form。

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

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          猜你喜欢
          • 2022-01-15
          • 2011-05-19
          • 2016-05-16
          • 2020-12-23
          • 2012-08-22
          • 1970-01-01
          • 2021-01-08
          • 2018-01-23
          • 1970-01-01
          相关资源
          最近更新 更多