Modèles Readonly dans L'interface D'administration de Django?

Comment puis-je faire un modèle complètement en lecture seule dans l'interface d'administration? C'est pour une sorte de table de journal, où j'utilise les fonctions d'administration pour rechercher, trier, filtrer, etc., mais il n'y a pas besoin de modifier le journal.

dans le cas où cela ressemble à un duplicata, voici pas ce que j'essaie de faire:

  • Je ne cherche pas readonly fields (même en faisant chaque champ readonly vous laisserait créer de nouveaux dossiers)
  • Je ne cherche pas à créer un readonly user : chaque utilisateur doit être readonly.
66
demandé sur Steve Bennett 2011-11-25 10:07:07

12 réponses

voir 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 (pour 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
répondu Pascal Polleunus 2015-11-05 11:50:12

l'administrateur est pour l'Édition, pas seulement l'Affichage (vous ne trouverez pas une permission" view"). Pour obtenir ce que vous voulez, vous devrez interdire l'ajout, la suppression et la lecture de tous les champs:

class MyAdmin(ModelAdmin):

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

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

(si vous interdisez de changer vous ne pourrez même pas voir les objets)

pour un code non testé qui essaie d'automatiser la mise en place de tous les champs en lecture seule voir ma réponse à tout le modèle en lecture seule

EDIT: également non testé, mais je viens de jeter un oeil à mon LogEntryAdmin et il a

readonly_fields = MyModel._meta.get_all_field_names()

Je ne sais pas si ça marchera dans tous les cas.

EDIT: QuerySet.supprimer() peut encore en vrac supprimer des objets. Pour contourner cela, fournir votre propre gestionnaire "objets" et la sous - classe QuerySet correspondante qui ne supprime pas-voir QuerySet supérieur.supprimer () dans Django

64
répondu Danny W. Adair 2017-05-23 12:18:16

voici deux classes que j'utilise pour faire un modèle et/ou c'est inlines lire seulement.

pour le modèle admin:

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

pour inlines:

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
répondu darklow 2017-02-03 11:45:37

si vous voulez que l'utilisateur se rende compte qu'il/elle ne peut pas l'éditer, 2 pièces manquent sur la première solution. Vous avez supprimer l'action Supprimer!

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

Seconde: lecture seule solution fonctionne bien sur la plaine des modèles. Mais il ne pas fonctionne si vous avez un modèle hérité avec des clés étrangères. Malheureusement, je ne connais pas encore la solution. Une bonne tentative est:

modèle entier en lecture seule

mais ça ne marche pas pour moi non plus.

et une dernière remarque, si vous voulez penser à une solution large, vous devez faire respecter que chaque ligne doit être en lecture seule aussi.

12
répondu Josir 2017-05-23 12:18:16

en fait, vous pouvez essayer cette solution simple:

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

    def has_add_permission(self, request):
        return False
  • actions = None : évite d'afficher la liste déroulante avec le "supprimer sélectionné ..."option
  • list_display_links = None : évite de cliquer dans les colonnes pour éditer cet objet
  • has_add_permission() retourner False évite de créer de nouveaux objets pour ce modèle
6
répondu Iván Zugnoni 2016-02-25 16:28:32

si la réponse acceptée ne fonctionne pas pour vous, essayez ceci:

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
répondu Wouter 2013-05-08 08:45:42

compilant les excellentes réponses de @darklow et @josir, plus en ajoutant un peu plus pour supprimer les boutons "Enregistrer" et "enregistrer et continuer" mène à (dans la syntaxe 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

et ensuite vous utilisez comme

class MyModelAdmin(ReadOnlyAdmin):
    pass

j'ai seulement essayé avec Django 1.11 / Python 3.

4
répondu Mark Chackerian 2017-05-18 14:46:53

la réponse acceptée devrait fonctionner, mais cela préservera aussi l'ordre d'affichage des champs en lecture seule. Vous n'avez pas non plus à hardcode le modèle avec cette solution.

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
répondu lastoneisbearfood 2014-01-16 02:44:33

j'ai rencontré la même exigence lorsque la nécessité de faire tous les champs en lecture seule pour certains utilisateurs dans django admin a fini par tirer parti sur le module django "django-admin-view-permission" sans rouler mon propre code. Si vous avez besoin de plus de contrôle à grain fin pour définir explicitement quels champs, alors vous aurez besoin d'étendre le module. Vous pouvez consulter le plugin en action ici

1
répondu Timothy 2016-12-20 04:45:14

cela a été ajouté à Django 2.1 qui est sorti le 8/1/18!

ModelAdmin.has_view_permission() est exactement comme la has_delete_permission, la has_change_permission et la has_add_permission existantes. Vous pouvez le lire dans les docs ici

des notes de version:

cela permet de donner aux utilisateurs un accès en lecture seule aux modèles de l'administrateur. ModelAdmin.has_view_permission() n'est pas nouvelle. Application être rétro-compatible en ce sens qu'il n'est pas nécessaire d'attribuer la " vue" autorisation, les utilisateurs qui disposent de l'autorisation "modifier" pour éditer objet.

1
répondu grrrrrr 2018-08-01 19:40:55

lecture seule => vues sur la permission

  1. pipenv install django-admin-view-permission
  2. ajouter "admin_view_permission" à INSTALLED_APPS dans les paramètres.py.comme ça.: "INSTALLED_APPS = [ "administr_view_permission",
  3. python manage.py migrate
  4. python manage.py runserver 6666

ok.amusez-vous avec la 'permission de vues '

0
répondu Xianhong Xu 2018-03-12 07:00:52

j'ai écrit une classe générique pour gérer la vue en lecture seule en fonction des permissions de L'utilisateur, y compris inlines;)

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

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 )

alors, nous pouvons juste hériter Normalement nos classes dans admin.py:

class ContactAdmin(ReadOnlyAdmin):
    list_display = ("name","email","whatever")
    readonly_fields = ("updated","created")
    inlines = ( PhoneInline, ... )
0
répondu Enric Mieza 2018-05-11 18:11:58