Как сделать экземпляр модели доступным только для чтения после его однократного сохранения?

Одна из функций проекта Django, который я пишу, - это отправка информационного бюллетеня. У меня есть модель Newsletter и функция send_newsletter, которые я зарегистрировал для прослушивания сигнала Newsletter от post_save. Когда объект информационного бюллетеня сохраняется через интерфейс администратора, send_newsletter проверяет, имеет ли значение created значение True, и если да, он действительно отправляет письмо.

Однако редактировать уже отправленный информационный бюллетень не имеет особого смысла по очевидным причинам. Есть ли способ сделать объект Newsletter доступным только для чтения после того, как он был сохранен?

Редактировать:

Я знаю, что могу переопределить метод save объекта, чтобы вызвать ошибку или ничего не делать, если объект существует. Однако я не вижу в этом смысла. Что касается первого, я не знаю, где отловить эту ошибку и как сообщить пользователю о том, что объект не был сохранен. Что касается последнего, то предоставление пользователю ложной обратной связи (интерфейс администратора сообщает, что сохранение выполнено успешно) не похоже на хорошее дело.

Что я действительно хочу, так это позволить пользователю использовать интерфейс администратора для написания информационного бюллетеня и его отправки, а затем просматривать информационные бюллетени, которые уже были отправлены. Я хотел бы, чтобы интерфейс администратора отображал данные для отправленных информационных бюллетеней в нередактируемом поле ввода без кнопки «Сохранить». В качестве альтернативы я бы хотел, чтобы кнопка «Сохранить» была неактивной.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
0
1 412
4

Ответы 4

Вы можете проверить, создается он или обновляется, в методе модели save:

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

Приведенный выше код вызовет исключение, если вы попытаетесь сохранить существующий объект. Для объектов, которые ранее не сохранялись, не заданы первичные ключи.

Предлагаемое чтение: Дзен Админа в глава 17 книги Джанго.

Резюме: администратор не предназначен для того, что вы пытаетесь сделать :(

Однако версия книги 1.0 охватывает только Django 0.96, и с тех пор произошло хорошее.

В Django 1.0 админка сайта более настраиваемый. Поскольку я сам не настраивал администратора, мне придется угадывать, основываясь на документации, но я бы сказал, что переопределение формы модели - ваш лучший выбор.

используйте readonlyadmin в ur amdin.py. Перечислите все поля, которые вы хотите сделать только для чтения. После создания объекта вы не можете редактировать их, а затем

используйте ссылку

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

скопируйте файл, а затем импортируйте в ur admin.py и используйте его

Что вы можете легко сделать, так это сделать все поля доступными только для чтения:

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. фрагмент кода, отвечающий за отображение элементов управления формы администратора (тег шаблона 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
    

Другие вопросы по теме