【问题标题】:How to make a model instance read-only after saving it once?保存一次后如何将模型实例设为只读?
【发布时间】:2010-10-02 17:48:16
【问题描述】:

我正在编写的 Django 项目中的一个功能是发送时事通讯。我有一个模型Newsletter 和一个函数send_newsletter,我已经注册了它来收听Newsletterpost_save 信号。当通过管理界面保存时事通讯对象时,send_newsletter 检查created 是否为 True,如果是,则它实际发送邮件。

但是,出于显而易见的原因,编辑已发送的时事通讯没有多大意义。有没有办法让 Newsletter 对象在保存后变为只读?

编辑:

我知道我可以覆盖对象的save 方法来引发错误,或者如果对象存在则什么都不做。但是,我没有看到这样做的意义。至于前者,我不知道在哪里捕获该错误以及如何向用户传达对象未保存的事实。至于后者,给用户错误的反馈(管理界面说保存成功)似乎不是一件好事。

我真正想要的是允许用户使用管理界面编写时事通讯并发送,然后浏览已经发送的时事通讯。我希望管理界面在不可编辑的输入框中显示已发送时事通讯的数据,而不需要“保存”按钮。或者,我希望“保存”按钮处于非活动状态。

【问题讨论】:

    标签: python django django-models django-admin django-signals


    【解决方案1】:

    您可以在模型的save方法中检查是创建还是更新:

    def save(self, *args, **kwargs):
        if self.pk:
            raise StandardError('Can\'t modify bla bla bla.')
        super(Payment, self).save(*args, **kwargs)
    

    如果您尝试保存现有对象,上述代码将引发异常。 之前未持久化的对象没有设置主键。

    【讨论】:

      【解决方案2】:

      推荐阅读:chapter 17 of the Django Book 中的管理之禅。

      总结:管理员不是为你想要做的事情而设计的:(

      然而,本书的 1.0 版本只涵盖了 Django 0.96,此后好事不断。

      在 Django 1.0 中,admin site 更加可定制。由于我自己没有自定义 admin,所以我必须根据文档进行猜测,但我会说 overriding the model form 是您最好的选择。

      【讨论】:

        【解决方案3】:

        在你的 amdin.py 中使用 readonlyadmin。列出你想要只读的所有字段。创建对象后你不能编辑它们

        使用链接

        http://www.djangosnippets.org/snippets/937/
        

        复制文件,然后导入你的 admin.py 并使用它

        【讨论】:

          【解决方案4】:

          您可以轻松做的就是将所有字段设为只读:

          class MyModelAdmin(ModelAdmin):
              form = ...
              def get_readonly_fields(self, request, obj=None):
                  if obj:
                      return MyModelAdmin.form.Meta.fields
                  else: # This is an addition
                      return []
          

          至于让存档消失,如果

          1. has_change_permission 返回 False 即使显示表单也不会禁用
          2. 负责呈现管理表单控件的代码 sn-p(admin_modify.submit_row 模板标签)不会无条件使用show_save=True

          无论如何,让那个人不被渲染的一种方法:

          1. 使用正确的逻辑创建 has_change_permission 的替代版本:

            class NoSaveModelAdminMixin(object):
                def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
                    response = super(NoSaveModelAdmin, self).render_change_form(request, context, add, change,form_url, obj)
                    response.context_data["has_change_permission"] = self.has_real_change_permission(request, obj)
                def has_real_change_permission(self, request, obj):
                    return obj==None
                def change_view(self, request, object_id, extra_context=None):
                    obj = self.get_object(request, unquote(object_id))
                    if not self.has_real_change_permission(request, obj) and request.method == 'POST':
                        raise PermissionDenied 
                    return super(NoSaveModelAdmin, self).change_view(request, object_id, extra_context=extra_context)
            
          2. 覆盖类似这样的 submit_row 模板标签:

            @admin_modify.register.inclusion_tag('admin/submit_line.html', takes_context=True)
            def submit_row(context):
                ...
                    'show_save': context['has_change_permission']
                ...
            
            admin_modify.submit_row = submit_row
            

          【讨论】:

            猜你喜欢
            • 2012-08-22
            • 1970-01-01
            • 2011-05-19
            • 2015-02-27
            • 1970-01-01
            • 2014-02-16
            • 2019-02-25
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多