django admin: vue en lecture seule séparée et vue de changement
j'aimerais utiliser l'administrateur django pour produire une vue en lecture seule d'un objet qui contient un bouton" Edit " qui vous commute à la vue de changement habituelle du même objet.
je sais comment utiliser les attributs readonly pour produire une vue en lecture seule, mais je ne sais pas comment produire deux vues, une en lecture seule et une qui permet des changements.
j'aimerais réutiliser autant de l'interface d'admin pour ce que possible, plutôt que d'écrire une vue à partir de zéro.
notez que cette question ne concerne pas les permissions: tous les utilisateurs auront la permission de changer les objets. C'est juste que je préférerais qu'ils n'utilisent pas change_view à moins qu'ils n'aient l'intention de faire des changements, réduisant ainsi le risque de changements accidentels ou simultanés.
5 réponses
Voici une réponse qui fait littéralement ce que j'ai demandé avec seulement quelques lignes de code et juste quelques changements de modèle:
class MyModelAdmin(admin.ModelAdmin):
fieldsets = [...]
def get_readonly_fields(self, request, obj=None):
if 'edit' not in request.GET:
return <list all fields here>
else:
return self.readonly_fields
maintenant L'URL habituelle pour le change_form produira un change_form en lecture seule, mais si vous ajoutez "?edit=1" à l'URL, vous serez en mesure de modifier.
le modèle change_form peut aussi être personnalisé selon que "?edit=1" est dans L'URL. Pour ce faire, mettez 'django.core.context_processors.request'
dans TEMPLATE_CONTEXT_PROCESSORS
dans settings.py
, puis utilisez request.GET.edit
dans le modèle.
par exemple, pour ajouter un bouton "Edit" lorsqu'il n'est pas en mode edit, insérer
{% if not request.GET.edit %}
<li><a href="?edit=1">Edit</a></li>
{% endif %}
juste après <ul class="object-tools">
dans change_form.html
.
comme autre exemple, remplacer change_form.html
par
{% if save_on_top and request.GET.edit %}{% submit_row %}{% endif %}
signifie que la ligne soumettre ne sera affichée qu'en mode édition. Un peut également masquer les boutons de suppression sur inlines, etc, en utilisant cette méthode.
pour référence, voici ce que j'ai mis dans settings.py
:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.contrib.messages.context_processors.messages',
# Above here are the defaults.
'django.core.context_processors.request',
)
je suggère de reconsidérer l'utilisation de vues personnalisées. Avec l'aide de générique DetailView
, vous aurez besoin d'écrire littéralement deux lignes de code. Le modèle ne nécessite pas beaucoup de travail. Vous prolongez juste la norme change_form.html template, overrading field_sets
block.
je sais comment utiliser les attributs readonly pour produire une vue en lecture seule, mais je ne sais pas comment produisez deux vues, une en lecture seule et une qui permet des changements.
vous pouvez en fait enregistrer un modèle dans l'admin deux fois[1], en utilisant proxy models . (Il y a quelques incohérences avec les permissions pour les modèles proxy, mais ce n'est peut-être pas un problème dans votre cas.)
il semble possible d'enregistrer plusieurs sites admin[2], aussi.
je voudrais réutiliser autant de l'administrateur interface pour cela que possible, plutôt que d'écrire une vue à partir de zéro.
la réutilisation de L'Interface en tant que telle a peu à voir avec les vues, étant la plupart du temps template - et la chose liée au style. View, cependant, devrait fournir le contexte de modèle nécessaire à la réutilisation de l'interface, comme vous l'avez correctement souligné.
si vous décidez d'aller avec plusieurs vues par un ModelAdmin
, alors il pourrait être utile pour vous de vérifier comment django-reversion
implémente le projet son intégration admin: reversion/admin.py .
Références
vous aurez besoin de changer le modèle que django admin utilise pour le formulaire modèle. Faites-le en lecture seule et ajoutez un bouton au modèle original lié à une autre url.
Note:
Je décourage fortement cette approche, vous n'empêcherez certainement pas les changements simultanés. Cela devrait être résolu avec verrouillage.
aussi, je recommande d'utiliser django-réversion pour garder l'histoire des objets et éliminer le risque de" changements accidentels".
vous pouvez créer une vue personnalisée et y afficher votre objet.
pour créer une vue personnalisée dans un module administrateur, outrepasser la méthode get_urls()
:
class MyAdmin(admin.ModelAdmin):
…
def get_urls(self):
urls = super(MyAdmin, self).get_urls()
my_urls = patterns('',
url(r'^custom_view/(?P<my_id>\d+)/$', self.admin_site.admin_view(self.custom_viem), name='custom_view')
)
return my_urls + urls
def custom_view(self, request, my_id):
"""Define your view function as usual in views.py
Link to this view using reverse('admin:custom_view')
"""
from myapp import views
return views.custom_view(request, my_id, self)
views.py :
def custom_view(request, object_id, model_admin):
admin_site = model_admin.admin_site
opts = model_admin.model._meta
my_object = get_object_or_404(MyObject, pk=object_id)
# do stuff
context = {
'admin_site': admin_site.name,
'opts': opts,
'title': _('My custom view'),
'root_path': '%s' % admin_site.root_path,
'app_label': opts.app_label,
'my_object': my_object,
}
return render_to_response('my_template.html', context,
context_instance=RequestContext(request))
dans votre template, utilisez {% extends "admin/base_site.html" %}
pour garder l'apparence d'administrateur.
le code ci-dessous est la mise en œuvre de l'administrateur en lecture seule en utilisant proxy models.
Models.py
//réel modèle
class CompetitionEntry(models.Model):
pass
//Proxy modèle
class ReviewEntry(CompetitionEntry):
class Meta:
proxy = True
def save(self, *args, **kwargs):
pass
admin.py
//modifiable admin
class CompetitionEntryAdmin(admin.ModelAdmin):
pass
admin.site.register(CompetitionEntry, CompetitionEntryAdmin)
// en lecture seule admin (affecter la seule autorisation "modifier" pour cela)
class ReviewEntryAdmin(admin.ModelAdmin):
pass
admin.site.register(ReviewEntry, ReviewEntryAdmin)