Comment puis-je rendre un modèle entièrement en lecture seule dans l'interface d'administration? C'est pour une sorte 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.
Dans le cas où cela ressemble à un double, voici ce pas ce que je suis en train de le faire:
- Je ne recherche pas de champs en lecture seule (même en rendant chaque champ en lecture seule vous permettrait toujours de créer de nouveaux enregistrements)
- Je ne cherche pas à créer un utilisateur en lecture seule : chaque utilisateur doit être en lecture seule.
django
django-admin
readonly
Steve Bennett
la source
la source
has_view_permission
a finalement été implémenté dans Django 2.1. Voir également stackoverflow.com/a/51641149 ci-dessous.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_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 %} <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 %}
la source
Model
, ou pour leModelAdmin
?ModelAdmin
.L'administrateur est destiné à l'édition, pas seulement à la visualisation (vous ne trouverez pas d'autorisation de «vue»). Afin d'obtenir ce que vous voulez, vous devrez interdire l'ajout, la suppression et la mise en lecture seule 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 tente d'automatiser la définition 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 œil à mon LogEntryAdmin et il a
readonly_fields = MyModel._meta.get_all_field_names()
Je ne sais pas si cela fonctionnera dans tous les cas.
EDIT: QuerySet.delete () peut toujours supprimer des objets en masse. Pour contourner ce problème, fournissez votre propre gestionnaire "d'objets" et la sous-classe QuerySet correspondante qui ne supprime pas - voir Remplacer QuerySet.delete () dans Django
la source
Voici deux classes que j'utilise pour créer un modèle et / ou il est en lecture seule.
Pour l'administrateur modèle:
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
la source
has_add_permission
enReadOnlyAdmin
ne prend que la demande en tant que paramètreSi vous voulez que l'utilisateur sache qu'il ne peut pas le modifier, il manque 2 pièces sur la première solution. Vous avez supprimé 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 ce n'est PAS fonctionne 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 non plus pour moi.
Et une note finale, si vous voulez réfléchir à une solution globale, vous devez faire en sorte que chaque inline soit également en lecture seule.
la source
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 le menu déroulant avec l'option "Supprimer la sélection ..."list_display_links = None
: évite de cliquer dans les colonnes pour éditer cet objethas_add_permission()
renvoyer False évite de créer de nouveaux objets pour ce modèlela source
Cela a été ajouté à Django 2.1 qui est sorti le 8/1/18!
ModelAdmin.has_view_permission()
est exactement comme les has_delete_permission, has_change_permission et has_add_permission existants. Vous pouvez lire à ce sujet dans la documentation iciÀ partir des notes de version:
la source
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
la source
Compiler les excellentes réponses de @darklow et @josir, et ajouter un peu plus pour supprimer les boutons «Enregistrer» et «Enregistrer et continuer» conduit à (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
Je n'ai essayé cela qu'avec Django 1.11 / Python 3.
la source
La réponse acceptée devrait fonctionner, mais cela préservera également l'ordre d'affichage des champs en lecture seule. Vous n'avez pas non plus besoin de coder en dur 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
la source
Avec Django 2.2, je le fais comme ceci:
@admin.register(MyModel) class MyAdmin(admin.ModelAdmin): readonly_fields = ('all', 'the', 'necessary', 'fields') actions = None # Removes the default delete action in list view 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
la source
readonly_fields
etactions
ne sont pas nécessairesavec django 2.2, l'administrateur 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')
la source
J'ai rencontré la même exigence lorsque je devais rendre tous les champs en lecture seule pour certains utilisateurs dans django admin a fini par tirer parti du module django "django-admin-view-permission" sans lancer mon propre code. Si vous avez besoin d'un contrôle plus fin pour définir explicitement les champs, vous devez étendre le module. Vous pouvez consulter le plugin en action ici
la source
lecture seule => autorisation de vues
pipenv install django-admin-view-permission
6666
ok.amusez-vous avec la permission 'vues'
la source
J'ai écrit une classe générique pour gérer la vue ReadOnly en fonction des autorisations de l'utilisateur, y compris en ligne;)
Dans 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
Dans 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 )
Ensuite, nous pouvons simplement hériter normalement de nos classes dans admin.py:
class ContactAdmin(ReadOnlyAdmin): list_display = ("name","email","whatever") readonly_fields = ("updated","created") inlines = ( PhoneInline, ... )
la source