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.

22
demandé sur Dan Christensen 2011-07-13 18:35:32

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',                                   
)
16
répondu Dan Christensen 2011-07-14 16:42:04

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

1
répondu Tony 2017-05-23 11:54:34

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".

0
répondu iElectric 2011-07-13 15:11:49

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.

0
répondu Thibault J 2011-07-13 15:32:25

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)
0
répondu Ryu_hayabusa 2014-02-23 18:19:44