Только для чтения моделей в интерфейсе администратора Django? - PullRequest
72 голосов
/ 25 ноября 2011

Как сделать модель полностью доступной только для чтения в интерфейсе администратора? Это своего рода таблица журналов, где я использую функции администратора для поиска, сортировки, фильтрации и т. Д., Но нет необходимости изменять журнал.

В случае, если это выглядит как дубликат, вот не , что я пытаюсь сделать:

  • Я не ищу только для чтения полей (даже если сделать каждое поле доступным только для чтения, вы сможете создавать новые записи)
  • Я не хочу создавать только для чтения пользователя : каждый пользователь должен быть доступен только для чтения.

Ответы [ 12 ]

65 голосов
/ 25 ноября 2011

Администратор предназначен для редактирования, а не только для просмотра (вы не найдете разрешения на «просмотр»).Чтобы достичь желаемого, вам нужно запретить добавление, удаление и делать все поля доступными только для чтения:

class MyAdmin(ModelAdmin):

    def has_add_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

(если вы запретите изменение, вы даже не увидите объекты)

Для некоторого непроверенного кода, который пытается автоматизировать установку всех полей только для чтения, см. Мой ответ на Вся модель только для чтения

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

readonly_fields = MyModel._meta.get_all_field_names()

Не знаю, будет ли это работать во всех случаях.

РЕДАКТИРОВАТЬ: QuerySet.delete () может по-прежнему массово удалять объекты.Чтобы обойти это, предоставьте свой собственный менеджер объектов и соответствующий подкласс QuerySet, который не удаляется - см. Переопределение QuerySet.delete () в Django

42 голосов
/ 10 ноября 2013

Вот два класса, которые я использую для создания модели, и / или она встроенная только для чтения.

Для модели администратора:

from django.contrib import admin

class ReadOnlyAdmin(admin.ModelAdmin):
    readonly_fields = []

    def get_readonly_fields(self, request, obj=None):
        return list(self.readonly_fields) + \
               [field.name for field in obj._meta.fields] + \
               [field.name for field in obj._meta.many_to_many]


    def has_add_permission(self, request):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

class MyModelAdmin(ReadOnlyAdmin):
    pass

Для строк:

class ReadOnlyTabularInline(admin.TabularInline):
    extra = 0
    can_delete = False
    editable_fields = []
    readonly_fields = []
    exclude = []

    def get_readonly_fields(self, request, obj=None):
        return list(self.readonly_fields) + \
               [field.name for field in self.model._meta.fields
                if field.name not in self.editable_fields and
                   field.name not in self.exclude]

    def has_add_permission(self, request):
        return False


class MyInline(ReadOnlyTabularInline):
    pass
16 голосов
/ 05 ноября 2015

См. https://djangosnippets.org/snippets/10539/

class ReadOnlyAdminMixin(object):
    """Disables all editing capabilities."""
    change_form_template = "admin/view.html"

    def __init__(self, *args, **kwargs):
        super(ReadOnlyAdminMixin, self).__init__(*args, **kwargs)
        self.readonly_fields = self.model._meta.get_all_field_names()

    def get_actions(self, request):
        actions = super(ReadOnlyAdminMixin, self).get_actions(request)
        del actions["delete_selected"]
        return actions

    def has_add_permission(self, request):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

    def save_model(self, request, obj, form, change):
        pass

    def delete_model(self, request, obj):
        pass

    def save_related(self, request, form, formsets, change):
        pass

шаблоны / админ / view.html

{% extends "admin/change_form.html" %}
{% load i18n %}

{% block submit_buttons_bottom %}
  <div class="submit-row">
    <a href="../">{% blocktrans %}Back to list{% endblocktrans %}</a>
  </div>
{% endblock %}

templates / admin / view.html (для Grappelli)

{% extends "admin/change_form.html" %}
{% load i18n %}

{% block submit_buttons_bottom %}
  <footer class="grp-module grp-submit-row grp-fixed-footer">
    <header style="display:none"><h1>{% trans "submit options"|capfirst context "heading" %}</h1></header>
    <ul>
       <li><a href="../" class="grp-button grp-default">{% blocktrans %}Back to list{% endblocktrans %}</a></li>
    </ul>
  </footer>
{% endblock %}
12 голосов
/ 03 ноября 2012

Если вы хотите, чтобы пользователь узнал, что он / она не может редактировать его, в первом решении отсутствуют 2 элемента.Вы удалили действие удаления!

class MyAdmin(ModelAdmin)
    def has_add_permission(self, request, obj=None):
        return False
    def has_delete_permission(self, request, obj=None):
        return False

    def get_actions(self, request):
        actions = super(MyAdmin, self).get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

Второе: решение только для чтения отлично работает на простых моделях.Но он НЕ работает, если у вас есть унаследованная модель с внешними ключами.К сожалению, я пока не знаю решения для этого.Хорошая попытка:

Вся модель только для чтения

Но она не работает и для меня.

И последнее замечание, есливы хотите придумать более широкое решение, вы должны обеспечить, чтобы каждая строка также была доступна только для чтения.

7 голосов
/ 25 февраля 2016

На самом деле вы можете попробовать это простое решение:

class ReadOnlyModelAdmin(admin.ModelAdmin):
    actions = None
    list_display_links = None
    # more stuff here

    def has_add_permission(self, request):
        return False
  • actions = None: избегает отображения выпадающего списка с опцией «Удалить выбранное ...»
  • list_display_links = None: избегает нажатия на столбцы для редактирования этого объекта
  • has_add_permission(), возвращая False, избегает создания новых объектов для этой модели
4 голосов
/ 01 августа 2018

Это было добавлено в Django 2.1, который был выпущен 01.08.18!

ModelAdmin.has_view_permission() точно так же, как существующие has_delete_permission, has_change_permission и has_add_permission.Вы можете прочитать об этом в документации здесь

Из заметок о выпуске:

Это позволяет предоставить пользователям доступ только для чтения к моделям в админке.ModelAdmin.has_view_permission () является новым.Реализация обратно совместима в том смысле, что нет необходимости назначать разрешение на «просмотр», чтобы позволить пользователям, имеющим разрешение «изменять», редактировать объекты.

4 голосов
/ 17 мая 2017

Компиляция превосходных ответов @darklow и @josir, а также добавление еще немного для удаления кнопок «Сохранить» и «Сохранить и продолжить» приводит к (в синтаксисе Python 3):

class ReadOnlyAdmin(admin.ModelAdmin):
    """Provides a read-only view of a model in Django admin."""
    readonly_fields = []

    def change_view(self, request, object_id, extra_context=None):
        """ customize add/edit form to remove save / save and continue """
        extra_context = extra_context or {}
        extra_context['show_save_and_continue'] = False
        extra_context['show_save'] = False
        return super().change_view(request, object_id, extra_context=extra_context)

    def get_actions(self, request):
        actions = super().get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

    def get_readonly_fields(self, request, obj=None):
        return list(self.readonly_fields) + \
           [field.name for field in obj._meta.fields] + \
           [field.name for field in obj._meta.many_to_many]

    def has_add_permission(self, request):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

и затем вы используете как

class MyModelAdmin(ReadOnlyAdmin):
    pass

Я пробовал это только с Django 1.11 / Python 3.

4 голосов
/ 08 мая 2013

Если принятый ответ не работает для вас, попробуйте это:

def get_readonly_fields(self, request, obj=None):
    readonly_fields = []
    for field in self.model._meta.fields:
        readonly_fields.append(field.name)

    return readonly_fields
2 голосов
/ 16 января 2014

Принятый ответ должен работать, но это также сохранит порядок отображения полей только для чтения.Вы также не должны жестко кодировать модель с этим решением.

class ReadonlyAdmin(admin.ModelAdmin):
   def __init__(self, model, admin_site):
      super(ReadonlyAdmin, self).__init__(model, admin_site)
      self.readonly_fields = [field.name for field in filter(lambda f: not f.auto_created, model._meta.fields)]

   def has_delete_permission(self, request, obj=None):
       return False
   def has_add_permission(self, request, obj=None):
       return False
1 голос
/ 20 декабря 2016

Я столкнулся с тем же требованием, когда мне нужно было сделать все поля доступными только для чтения для определенных пользователей в django admin. В итоге я использовал модуль django "django-admin-view-Разрешение", не катя мой собственный код.Если вам нужно более детализированное управление, чтобы явно определить, какие поля вам нужно расширить модуль.Вы можете проверить плагин в действии здесь

...