Désactiver le lien pour modifier l'objet dans l'admin de django (afficher la liste seulement)?
Dans Django admin, je veux désactiver les liens fournis sur la page" Sélectionner un élément à modifier " afin que les utilisateurs ne puissent aller nulle part pour modifier l'élément. (Je vais limiter ce que les utilisateurs peuvent faire avec cette liste à un ensemble d'actions déroulantes - pas d'édition réelle des champs).
je vois que Django a la capacité de choisissez les champs qui affichent le lien cependant, je ne vois pas comment je peux avoir aucun.
class HitAdmin(admin.ModelAdmin):
list_display = ('user','ip','user_agent','hitcount')
search_fields = ('ip','user_agent')
date_hierarchy = 'created'
list_display_links = [] # doesn't work, goes to default
tous idées comment obtenir ma liste d'objets sans aucun lien à éditer?
9 réponses
je voulais un visualiseur de Log comme liste seulement.
je l'ai eu à travailler comme cela:
class LogEntryAdmin(ModelAdmin):
actions = None
list_display = (
'action_time', 'user',
'content_type', 'object_repr',
'change_message')
search_fields = ['=user__username', ]
fieldsets = [
(None, {'fields':()}),
]
def __init__(self, *args, **kwargs):
super(LogEntryAdmin, self).__init__(*args, **kwargs)
self.list_display_links = (None, )
C'est une sorte de mix entre les deux réponses.
Si vous venez de le faire self.list_display_links = ()
il montrera le lien, de toute façon parce que le template-tag
code (templatetags/admin_list.py) vérifie à nouveau si la liste est vide.
faire ceci correctement nécessite deux étapes:
- masquer le lien d'édition, pour que personne ne trébuche sur la page de détail (changer la vue) par erreur.
- Modifier la modifier la vue de rediriger retour à la liste afficher.
la deuxième partie est importante: si vous ne le faites pas, les gens pourront tout de même accéder à la vue change en entrant directement une URL (ce que vous ne voulez probablement pas). Cela est étroitement lié à ce que L'OWASP terme an "Unsecure Direct Object Reference".
dans le cadre de cette réponse je construirai un ReadOnlyMixin
classe qui peut être utilisé pour fournir toutes les fonctionnalités montré.
Cacher le lien D'édition
Django 1.7 rend cela vraiment facile: vous venez de mettre list_display_links
None
.
class ReadOnlyMixin(): # Add inheritance from "object" if using Python 2
list_display_links = None
Django 1.6 (et probablement plus tôt) ne rend pas cela si simple. Beaucoup de réponses à cette question ont suggéré primordial __init__
afin de mettre en list_display_links
après que l'objet a été construit, mais cela le rend plus difficile à réutiliser (nous ne pouvons Outrepasser le constructeur qu'une seule fois).
je pense que la meilleure option est de les remplacer Django get_list_display_links
méthode comme suit:
def get_list_display_links(self, request, list_display):
"""
Return a sequence containing the fields to be displayed as links
on the changelist. The list_display parameter is the list of fields
returned by get_list_display().
We override Django's default implementation to specify no links unless
these are explicitly set.
"""
if self.list_display_links or not list_display:
return self.list_display_links
else:
return (None,)
cela rend notre mixin facile à utiliser: il cache le lien d'édition par défaut mais nous permet de l'ajouter de nouveau si nécessaire pour une vue d'administrateur particulière.
redirection vers la vue Liste
nous pouvons changer le comportement du page de détail (change view) en remplaçant le change_view
méthode. Voici une extension à la technique suggérée par Chris Pratt qui trouve automatiquement la bonne page:
enable_change_view = False
def change_view(self, request, object_id, form_url='', extra_context=None):
"""
The 'change' admin view for this model.
We override this to redirect back to the changelist unless the view is
specifically enabled by the "enable_change_view" property.
"""
if self.enable_change_view:
return super(ReportMixin, self).change_view(
request,
object_id,
form_url,
extra_context
)
else:
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
opts = self.model._meta
url = reverse('admin:{app}_{model}_changelist'.format(
app=opts.app_label,
model=opts.model_name,
))
return HttpResponseRedirect(url)
là Encore, c'est personnalisable par basculement enable_change_view
True
vous pouvez revenir sur la page des détails.
supprimer le " Ajouter ITEM" Bouton
enfin, vous pourriez vouloir outrepasser les méthodes suivantes afin d'empêcher les gens d'ajouter ou de supprimer de nouvelles article.
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return False
Ces modifications suivantes sont apportées:
- désactiver le " Add item" bouton
- empêcher les gens d'ajouter directement des articles en ajoutant
/add
à L'URL - prévenir les supprimer en vrac
enfin vous pouvez supprimer le " Delete selected éléments" l'action en modifiant l' actions
paramètre.
Mettre
Voici la version complète mixin:
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
class ReadOnlyMixin(): # Add inheritance from "object" if using Python 2
actions = None
enable_change_view = False
def get_list_display_links(self, request, list_display):
"""
Return a sequence containing the fields to be displayed as links
on the changelist. The list_display parameter is the list of fields
returned by get_list_display().
We override Django's default implementation to specify no links unless
these are explicitly set.
"""
if self.list_display_links or not list_display:
return self.list_display_links
else:
return (None,)
def change_view(self, request, object_id, form_url='', extra_context=None):
"""
The 'change' admin view for this model.
We override this to redirect back to the changelist unless the view is
specifically enabled by the "enable_change_view" property.
"""
if self.enable_change_view:
return super(ReportMixin, self).change_view(
request,
object_id,
form_url,
extra_context
)
else:
opts = self.model._meta
url = reverse('admin:{app}_{model}_changelist'.format(
app=opts.app_label,
model=opts.model_name,
))
return HttpResponseRedirect(url)
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return False
en tant qu'utilisateur, omat, mentionné dans un commentaire ci-dessus, toute tentative de simplement supprimer les liens n'empêche pas les utilisateurs d'accéder encore à la page de changement manuellement. Cependant, cela aussi est assez facile à corriger:
class MyModelAdmin(admin.ModelAdmin)
# Other stuff here
def change_view(self, request, obj=None):
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
return HttpResponseRedirect(reverse('admin:myapp_mymodel_changelist'))
à Django 1.7 et plus tard, vous pouvez faire
class HitAdmin(admin.ModelAdmin):
list_display_links = None
Dans votre modèle de set admin:
list_display_links = (None,)
ça devrait le faire. (Fonctionne en tout cas au 1.1.1.)
Lien vers les docs: list_display_links
il n'y a pas de façon supportée de faire cela.
en Regardant le code, il semble qu'il définit automatiquement ModelAdmin.list_display_links
au premier élément si vous ne le mettez à rien. Ainsi, la façon la plus simple pourrait être d'Outrepasser le __init__
dans votre ModelAdmin
sous-classe d'annuler cet attribut lors de l'initialisation:
class HitAdmin(admin.ModelAdmin):
list_display = ('user','ip','user_agent','hitcount')
search_fields = ('ip','user_agent')
date_hierarchy = 'created'
def __init__(self, *args, **kwargs):
super(HitAdmin, self).__init__(*args, **kwargs)
self.list_display_links = []
cela semble fonctionner, après un test très superficiel. Je ne peux pas garantir qu'il ne cassera rien ailleurs, ou qu'il ne sera pas brisé par de futurs changements à Django, si.
Modifier après le commentaire:
Pas besoin de patch la source, cela devrait fonctionner:
def __init__(self, *args, **kwargs):
if self.list_display_links:
unset_list_display = True
else:
unset_list_display = False
super(HitAdmin, self).__init__(*args, **kwargs)
if unset_list_display:
self.list_display_links = []
mais je doute fortement que N'importe quel patch soit accepté dans Django, puisque cela casse quelque chose que le code fait explicitement pour le moment.
Juste pour les notes, vous pouvez modifier changelist_view:
class SomeAdmin(admin.ModelAdmin):
def changelist_view(self, request, extra_context=None):
self.list_display_links = (None, )
return super(SomeAdmin, self).changelist_view(request, extra_context=None)
Cela fonctionne très bien pour moi.
Vous pourriez également être ridiculement hacky à ce sujet (si vous ne voulez pas de chichi avec prépondérant init
) et fournir une valeur pour le premier élément qui ressemble fondamentalement à ceci:
</a>My non-linked value<a>
je sais, je sais, pas très jolie, mais peut-être moins d'anxiété à propos de casser quelque chose ailleurs puisque tout ce que nous faisons est de changer la marge.
voici un exemple de code sur la façon dont cela fonctionne:
class HitAdmin(admin.ModelAdmin):
list_display = ('user_no_link','ip','user_agent','hitcount')
def user_no_link(self, obj):
return u'</a>%s<a>' % obj
user_no_link.allow_tags = True
user_no_link.short_description = "user"
note latérale: vous pouvez aussi améliorer la lisibilité de la sortie (puisque vous ne voulez pas qu'il soit un lien) en retournant return u'%s' % obj.get_full_name()
qui pourrait être assez soigné selon votre cas d'utilisation.
avec django 1.6.2 vous pouvez faire comme ceci:
class MyAdmin(admin.ModelAdmin):
def get_list_display_links(self, request, list_display):
return []
il masquera tous les liens générés automatiquement.