简体   繁体   中英

How to make a model instance read-only after saving it once?

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.

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?

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.

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.

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

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.

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

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.

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.

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

  1. has_change_permission returning False wouldnt disable even displaying the form
  2. the code snippet responsible for rendering the admin form controls (the admin_modify.submit_row templatetag), wouldnt use show_save=True unconditionally.

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

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

     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:

     @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 

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

use the link

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM