Readonly modele w interfejsie admina Django?

Jak Zrobić model Całkowicie tylko do odczytu w interfejsie administratora? Jest to rodzaj tabeli dziennika, gdzie używam funkcji administratora do wyszukiwania, sortowania, filtrowania itp., ale nie ma potrzeby modyfikowania dziennika.

W przypadku, gdy wygląda to jak duplikat, oto NIE co próbuję zrobić:

  • nie szukam pól readonly (nawet zrobienie każdego pola readonly pozwoli na tworzenie nowych rekordów)
  • nie chcę tworzyć readonly user : każdy użytkownik powinien być tylko readonly.
Author: Steve Bennett, 2011-11-25

12 answers

Zobacz 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

Templates / admin / 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 (dla 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 %}
 11
Author: Pascal Polleunus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-05 11:50:12

Administrator służy do edycji, a nie tylko do przeglądania (nie znajdziesz uprawnień "widoku"). Aby osiągnąć to, co chcesz, musisz zabronić dodawania, usuwania i uczynić wszystkie pola readonly:

class MyAdmin(ModelAdmin):

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

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

(jeśli zabronisz zmiany, nie zobaczysz nawet obiektów)

Dla jakiegoś nieprzetestowanego kodu, który próbuje zautomatyzować ustawianie wszystkich pól tylko do odczytu zobacz moją odpowiedź na cały model jako Tylko do odczytu

EDIT: również niesprawdzony, ale po prostu spojrzałem na mój LogEntryAdmin i to has

readonly_fields = MyModel._meta.get_all_field_names()
Nie wiem, czy to zadziała we wszystkich przypadkach.

EDIT: QuerySet.delete () może nadal masowo usuwać obiekty. Aby to obejść, podaj swój własny menedżer "obiektów" i odpowiadającą mu podklasę QuerySet, która nie jest usuwana - zobacz nadpisywanie QuerySet.delete () in Django

 64
Author: Danny W. Adair,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:16

Oto dwie klasy, których używam do tworzenia modelu i / lub jest tylko do odczytu w liniach.

Dla modela admina:

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

Dla linii:

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
 40
Author: darklow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-03 11:45:37

Jeśli chcesz, aby użytkownik wiedział, że nie może go edytować, brakuje 2 elementów na pierwszym rozwiązaniu. Musisz usunąć akcję Usuń!

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

Po drugie: rozwiązanie readonly działa dobrze na zwykłych modelach. Ale to działa NIE Jeśli masz odziedziczony model z kluczami obcymi. Niestety, nie znam jeszcze rozwiązania. Dobra próba to:

Cały model jako Tylko do odczytu

Ale dla mnie to też nie działa.

I finał uwaga, jeśli chcesz myśleć o szerokim rozwiązaniu, musisz wymusić, że każda linia inline musi być również readonly.

 12
Author: Josir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:16

W rzeczywistości można spróbować tego prostego rozwiązania:

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

    def has_add_permission(self, request):
        return False
  • actions = None: unika wyświetlania rozwijanej listy z "Usuń zaznaczone ..."opcja
  • list_display_links = None: unika klikania w kolumny, aby edytować ten obiekt
  • has_add_permission() zwracanie False unika tworzenia nowych obiektów dla tego modelu
 6
Author: Iván Zugnoni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-25 16:28:32

Jeśli zaakceptowana odpowiedź nie działa dla ciebie, spróbuj tego:

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
 4
Author: Wouter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-08 08:45:42

Kompilacja doskonałych odpowiedzi @darklow i @ josir, plus dodanie nieco więcej, aby usunąć przyciski "Zapisz" i "zapisz i kontynuuj" prowadzi do (w składni Pythona 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

A potem używasz jak

class MyModelAdmin(ReadOnlyAdmin):
    pass

Próbowałem tego tylko z Django 1.11 / Python 3.

 4
Author: Mark Chackerian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-18 14:46:53

Zaakceptowana odpowiedź powinna działać, ale zachowa to również kolejność wyświetlania pól readonly. Nie musisz również kodować na twardo modelu za pomocą tego rozwiązania.

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
 2
Author: lastoneisbearfood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-16 02:44:33

Spotkałem się z tym samym wymogiem, gdy potrzebowałem aby wszystkie pola były tylko odczytywane dla niektórych użytkowników w django admin skończyło się na wykorzystaniu modułu django "django-admin-view-permission" bez włączania własnego kodu. Jeśli potrzebujesz bardziej drobnoziarnistej kontroli, aby jawnie zdefiniować, które pola, musisz rozszerzyć moduł. Możesz sprawdzić wtyczkę w działaniu tutaj

 1
Author: Timothy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-20 04:45:14

To zostało dodane do Django 2.1, które zostało wydane 8/1/18!

ModelAdmin.has_view_permission() jest podobnie jak istniejące has_delete_permission, has_change_permission i has_add_permission. Możesz o tym przeczytać w dokumentach tutaj

Z informacji o wydaniu:

Pozwala to dać użytkownikom dostęp tylko do odczytu do modeli w panelu administracyjnym. ModelAdmin.has_view_permission() jest nowe. Realizacja jest kompatybilne wstecz, ponieważ nie ma potrzeby przypisywania " widoku" pozwolenie aby umożliwić użytkownikom, którzy mają uprawnienia "Zmień", edytowanie obiektów.

 1
Author: grrrrrr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-01 19:40:55

Read-only => views permission

  1. pipenv install django-admin-view-permission
  2. Dodaj 'admin_view_permission' do INSTALLED_APPS w Ustawieniach. py. w ten sposób: "INSTALLED_APPS = [ "admin_view_permission",
  3. python manage.py migrate
  4. python manage.py runserver 6666

Ok.baw się dobrze z uprawnieniami "views"

 0
Author: Xianhong Xu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-12 07:00:52

Napisałem klasę generyczną do obsługi ReadOnly view w zależności od uprawnień użytkownika, w tym linii;)

W models.py:

class User(AbstractUser):
    ...
    def is_readonly(self):
        if self.is_superuser:
            return False
        # make readonly all users not in "admins" group
        adminGroup = Group.objects.filter(name="admins")
        if adminGroup in self.groups.all():
            return False
        return True

W admin.py:

# read-only user filter class for ModelAdmin
class ReadOnlyAdmin(admin.ModelAdmin):
    def __init__(self, *args, **kwargs):
        # keep initial readonly_fields defined in subclass
        self._init_readonly_fields = self.readonly_fields
        # keep also inline readonly_fields
        for inline in self.inlines:
            inline._init_readonly_fields = inline.readonly_fields
        super().__init__(*args,**kwargs)
    # customize change_view to disable edition to readonly_users
    def change_view( self, request, object_id, form_url='', extra_context=None ):
        context = extra_context or {}
        # find whether it is readonly or not 
        if request.user.is_readonly():
            # put all fields in readonly_field list
            self.readonly_fields = [ field.name for field in self.model._meta.get_fields() if not field.auto_created ]
            # readonly mode fer all inlines
            for inline in self.inlines:
                inline.readonly_fields = [field.name for field in inline.model._meta.get_fields() if not field.auto_created]
            # remove edition buttons
            self.save_on_top = False
            context['show_save'] = False
            context['show_save_and_continue'] = False
        else:
            # if not readonly user, reset initial readonly_fields
            self.readonly_fields = self._init_readonly_fields
            # same for inlines
            for inline in self.inlines:
                inline.readonly_fields = self._init_readonly_fields
        return super().change_view(
                    request, object_id, form_url, context )
    def save_model(self, request, obj, form, change):
        # disable saving model for readonly users
        # just in case we have a malicious user...
        if request.user.is_readonly():
            # si és usuari readonly no guardem canvis
            return False
        # if not readonly user, save model
        return super().save_model( request, obj, form, change )

Wtedy możemy po prostu dziedziczyć Normalnie nasze klasy w admin.py:

class ContactAdmin(ReadOnlyAdmin):
    list_display = ("name","email","whatever")
    readonly_fields = ("updated","created")
    inlines = ( PhoneInline, ... )
 0
Author: Enric Mieza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-11 18:11:58