如何在保存一次后将模型实例设为只读?

时间:2022-04-07 05:35:25

One of the functionalities in a Django project I am writing is sending a newsletter. I have a model, Newsletter and a function, send_newsletter, which I have registered to listen to Newsletter's post_save signal. When the newsletter object is saved via the admin interface, send_newsletter checks if created is True, and if yes it actually sends the mail.

我正在写的Django项目的一个功能是发送简报。我有一个模型,时事通讯和一个函数send_newsletter,我已注册收听Newsletter的post_save信号。通过管理界面保存新闻稿对象时,send_newsletter会检查创建的是否为True,如果是,则实际发送邮件。

However, it doesn't make much sense to edit a newsletter that has already been sent, for the obvious reasons. Is there a way of making the Newsletter object read-only once it has been saved?

但是,由于显而易见的原因,编辑已发送的简报没有多大意义。有没有办法让Newsletter对象在保存后成为只读对象?

Edit:

I know I can override the save method of the object to raise an error or do nothin if the object existed. However, I don't see the point of doing that. As for the former, I don't know where to catch that error and how to communicate the user the fact that the object wasn't saved. As for the latter, giving the user false feedback (the admin interface saying that the save succeded) doesn't seem like a Good Thing.

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

What I really want is allow the user to use the Admin interface to write the newsletter and send it, and then browse the newsletters that have already been sent. I would like the admin interface to show the data for sent newsletters in an non-editable input box, without the "Save" button. Alternatively I would like the "Save" button to be inactive.

我真正想要的是允许用户使用Admin界面编写新闻稿并发送,然后浏览已发送的新闻稿。我希望管理界面在不可编辑的输入框中显示已发送简讯的数据,而不使用“保存”按钮。或者,我希望“保存”按钮不活动。

4 个解决方案

#1


You can check if it is creation or update in the model's save method:

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

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

Code above will raise an exception if you try to save an existing object. Objects not previously persisted don't have their primary keys set.

如果您尝试保存现有对象,上面的代码将引发异常。以前未保留的对象没有设置其主键。

#2


Suggested reading: The Zen of Admin in chapter 17 of the Django Book.

推荐阅读:Django书第17章中的管理之禅。

Summary: The admin is not designed for what you're trying to do :(

摘要:管理员不是为您尝试做的而设计的:(

However, the 1.0 version of the book covers only Django 0.96, and good things have happened since.

但是,这本书的1.0版本仅涵盖了Django 0.96,自那以后发生了很多好事。

In Django 1.0, the admin site is more customizable. Since I haven't customized admin myself, I'll have to guess based on the docs, but I'd say overriding the model form is your best bet.

在Django 1.0中,管理站点更具可定制性。由于我自己没有自定义管理员,我必须根据文档进行猜测,但我会说压倒模型表格是最好的选择。

#3


use readonlyadmin in ur amdin.py.List all the fields which u want to make readonly.After creating the object u canot edit them then

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

use the link

使用链接

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

copy the file and then import in ur admin.py and used it

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

#4


What you can easily do, is making all fields readonly:

您可以轻松完成的任务是使所有字段只读:

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

As for making the Save disappear, it would be much easier if

至于使Save消失,如果更容易

  1. has_change_permission returning False wouldnt disable even displaying the form
  2. has_change_permission返回False甚至不会禁用显示表单

  3. the code snippet responsible for rendering the admin form controls (the admin_modify.submit_row templatetag), wouldnt use show_save=True unconditionally.
  4. 负责呈现管理表单控件的代码片段(admin_modify.submit_row模板标签),不会无条件地使用show_save = True。

Anyways, one way of making that guy not to be rendered :

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

  1. Create an alternate version of has_change_permission, with proper logic:

    使用适当的逻辑创建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. Override the submit_row templatetag similar to this:

    覆盖与此类似的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
    

#1


You can check if it is creation or update in the model's save method:

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

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

Code above will raise an exception if you try to save an existing object. Objects not previously persisted don't have their primary keys set.

如果您尝试保存现有对象,上面的代码将引发异常。以前未保留的对象没有设置其主键。

#2


Suggested reading: The Zen of Admin in chapter 17 of the Django Book.

推荐阅读:Django书第17章中的管理之禅。

Summary: The admin is not designed for what you're trying to do :(

摘要:管理员不是为您尝试做的而设计的:(

However, the 1.0 version of the book covers only Django 0.96, and good things have happened since.

但是,这本书的1.0版本仅涵盖了Django 0.96,自那以后发生了很多好事。

In Django 1.0, the admin site is more customizable. Since I haven't customized admin myself, I'll have to guess based on the docs, but I'd say overriding the model form is your best bet.

在Django 1.0中,管理站点更具可定制性。由于我自己没有自定义管理员,我必须根据文档进行猜测,但我会说压倒模型表格是最好的选择。

#3


use readonlyadmin in ur amdin.py.List all the fields which u want to make readonly.After creating the object u canot edit them then

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

use the link

使用链接

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

copy the file and then import in ur admin.py and used it

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

#4


What you can easily do, is making all fields readonly:

您可以轻松完成的任务是使所有字段只读:

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

As for making the Save disappear, it would be much easier if

至于使Save消失,如果更容易

  1. has_change_permission returning False wouldnt disable even displaying the form
  2. has_change_permission返回False甚至不会禁用显示表单

  3. the code snippet responsible for rendering the admin form controls (the admin_modify.submit_row templatetag), wouldnt use show_save=True unconditionally.
  4. 负责呈现管理表单控件的代码片段(admin_modify.submit_row模板标签),不会无条件地使用show_save = True。

Anyways, one way of making that guy not to be rendered :

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

  1. Create an alternate version of has_change_permission, with proper logic:

    使用适当的逻辑创建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. Override the submit_row templatetag similar to this:

    覆盖与此类似的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