Целая модель как только для чтения

Есть ли способ создать модель только для чтения в admin django? но я имею в виду всю модель. Итак, не добавляйте, не удаляете, не меняете, просто видите объекты и поля, все как только для чтения?

Ответ 1

ModelAdmin предоставляет hook get_readonly_fields() - следующее непроверено, моя идея состоит в том, чтобы определить все поля, как это делает ModelAdmin, без использования рекурсии с самими полями readonly:

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

тогда подкласс /mixin этого администратора, если он должен быть администратором только для чтения.

Чтобы добавить/удалить, и чтобы их кнопки исчезли, вы, вероятно, также захотите добавить

    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 (lookup или ваше переопределение) возвращает False, вы не попадаете в представление изменения объекта - и ссылка на него даже не будет показана. Было бы здорово, если бы это произошло, и по умолчанию get_readonly_fields() проверил разрешение на изменение и в этом случае установил все поля только для чтения, как указано выше. Таким образом, не-чейнджеры могли бы, по крайней мере, просматривать данные... учитывая, что текущая структура администратора предполагает view = edit, как указывает jathanism, это, вероятно, потребует введения разрешения "view" поверх добавления/изменения/удаления...

РЕДАКТИРОВАТЬ: относительно установки всех полей только для чтения, также непроверенных, но перспективных:

readonly_fields = MyModel._meta.get_all_field_names()

EDIT: здесь еще один

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

Ответ 2

Вы можете настроить свои классы ModelAdmin с помощью атрибута readonly_fields. Подробнее см. .

Ответ 3

Как "разрешения на просмотр" не попадет в Django 1.11, к сожалению, здесь решение, которое делает ваш ModelAdmin только, делая как сохранение изменений модели, так и добавление записей журнала истории моделей no-op.

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 с встроенным false. Если вы не сочувствуете вспомогательной функции вне класса, переместите его в класс, назовите его no_op или что-то еще или переопределите затронутые атрибуты обычным def s. Меньше DRY, но если вам все равно...)

Это будет:

  • удалить раскрывающийся список действий (с "удалить" ) в представлении списка
  • запретить добавление новых записей модели
  • запретить удаление существующих записей модели
  • избегать создания записей журнала в истории модели
  • избежать отображения "было успешно изменено" после сохранения
  • избежать сохранения изменений в базе данных

Это не будет:

  • удалите или замените две кнопки "Сохранить и продолжить редактирование" и "СОХРАНИТЬ" (что было бы неплохо улучшить работу пользователя)

Обратите внимание, что get_all_field_names (как упоминалось в принятом ответе) было удалено в Django 1.10. Протестировано с помощью Django 1.10.5.

Ответ 4

У меня был похожий сценарий, где:

  • Пользователь должен иметь возможность создавать объекты модели
  • Пользователь должен иметь возможность просматривать список объектов модели
  • Пользователь SHOULD'NT сможет редактировать объект после его создания.

1. Переопределение просмотра изменений

Поскольку возможно переопределить change_view() в ModelAdmin, мы можем использовать это, чтобы предотвратить редактирование экземпляров модели после их создания. Вот пример, который я использовал:

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. Условно изменение прав на редактирование

Я также понял, что docs интерпретируют результат ModelAdmin.has_change_permission() по-разному:

Должен возвращать True, если разрешено редактирование obj, в противном случае 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, позволяющие нежелательным глазам просматривать список изменений?

Ответ 5

В соответствии с моим тестом на 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]         
  ))