103 votes

Modèles en lecture seule dans l'interface d'administration de Django ?

Comment puis-je rendre un modèle complètement en lecture seule dans l'interface d'administration? Il s'agit d'un type de table de journal, où j'utilise les fonctionnalités d'administration pour rechercher, trier, filtrer, etc., mais il n'est pas nécessaire de modifier le journal.

Si cela semble être un doublon, voici ce que je n'essaie pas de faire:

  • Je ne cherche pas des champs en lecture seule (même rendre chaque champ en lecture seule permettrait toujours de créer de nouveaux enregistrements)
  • Je ne cherche pas à créer un utilisateur en lecture seule: chaque utilisateur devrait être en lecture seule.

78voto

Danny W. Adair Points 2914

L'administration est pour l'édition, pas seulement pour la visualisation (vous ne trouverez pas de permission "visualisation"). Pour obtenir ce que vous voulez, vous devrez interdire l'ajout, la suppression, et rendre tous les champs en lecture seule :

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 les modifications, vous ne verrez même pas les objets)

Pour un code non testé qui tente d'automatiser le réglage de tous les champs en lecture seule, consultez ma réponse à Whole model as read-only

EDIT : Cela rend tous les champs en lecture seule :

readonly_fields = [field.name for field in MyModel._meta.get_fields()]

EDIT : QuerySet.delete() peut encore supprimer en masse des objets. Pour contourner cela, fournissez votre propre gestionnaire "objects" et une sous-classe QuerySet correspondante qui ne supprime pas - voir Overriding QuerySet.delete() in Django

58voto

darklow Points 456

Voici deux classes que j'utilise pour rendre un modèle et/ou ses inlines en lecture seule.

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 les 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

25voto

Pascal Polleunus Points 887

Consultez https://djangosnippets.org/snippets/10539/

class ReadOnlyAdminMixin(object):
    """Désactive toutes les capacités de modification."""
    change_form_template = "admin/view.html"

    def __init__(self, *args, **kwargs):
        super(ReadOnlyAdminMixin, self).__init__(*args, **kwargs)
        self.readonly_fields = [f.name for f in self.model._meta.get_fields()]

    def get_actions(self, request):
        actions = super(ReadOnlyAdminMixin, self).get_actions(request)
        del_action = "delete_selected"
        if del_action in actions:
            del actions[del_action]
        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 %}

    {% blocktrans %}Retour à la liste{% endblocktrans %}

{% endblock %}

templates/admin/view.html (pour Grappelli)

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

{% block submit_buttons_bottom %}

    {% trans "options de soumission"|capfirst context "heading" %}

       {% blocktrans %}Retour à la liste{% endblocktrans %}

{% endblock %}

18voto

cheng10 Points 56

Avec django 2.2+, l'administration en lecture seule peut être aussi simple que :

class ReadOnlyAdminMixin:
    def has_add_permission(self, request):
        return False

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

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

class LogEntryAdmin(ReadOnlyAdminMixin, admin.ModelAdmin):
    list_display = ('id', 'user', 'action_flag', 'content_type', 'object_repr')

13voto

Josir Points 243

Si vous souhaitez que l'utilisateur soit conscient qu'il ne peut pas le modifier, il manque 2 pièces sur la première solution. Vous devez supprimer l'action de suppression!

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

Deuxièmement : la solution en lecture seule fonctionne bien sur les modèles simples. Mais elle ne fonctionne pas si vous avez un modèle hérité avec des clés étrangères. Malheureusement, je ne connais pas encore la solution pour cela. Une bonne tentative est :

Modèle entier en lecture seule

Mais cela ne fonctionne pas pour moi non plus.

Et enfin, si vous voulez réfléchir à une solution globale, vous devez également imposer que chaque élément en ligne soit en lecture seule.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X