177 votes

Plusieurs ModelAdmins/views pour le même modèle dans l'administration de Django

Comment puis-je créer plusieurs ModelAdmin pour le même modèle, chacun étant personnalisé différemment et lié à des URL différentes ?

Disons que j'ai un modèle Django appelé Posts. Par défaut, la vue d'administration de ce modèle listera tous les objets Post.

Je sais que je peux personnaliser la liste des objets affichés sur la page de diverses manières en définissant des variables telles que list_display ou en remplaçant la fonction queryset dans mon ModelAdmin comme suit :

class MyPostAdmin(admin.ModelAdmin):
    list_display = ('title', 'pub_date')

    def queryset(self, request):
        request_user = request.user
        return Post.objects.filter(author=request_user)

admin.site.register(MyPostAdmin, Post)

Par défaut, il est accessible à l'URL /admin/myapp/post . Cependant, j'aimerais avoir plusieurs vues/ModelAdmins du même modèle, par exemple /admin/myapp/post énumérerait tous les objets postaux, et /admin/myapp/myposts énumérerait tous les messages appartenant à l'utilisateur, et /admin/myapp/draftpost pourrait répertorier tous les messages qui n'ont pas encore été publiés. (ce ne sont que des exemples, mon cas d'utilisation réel est plus complexe)

Vous ne pouvez pas enregistrer plus d'un ModelAdmin pour le même modèle (cela entraîne une erreur d'enregistrement). AlreadyRegistered exception). Idéalement, j'aimerais obtenir ceci sans en mettant tout dans une seule classe ModelAdmin et en écrivant ma propre fonction 'urls' pour retourner un queryset différent en fonction de l'URL.

J'ai jeté un coup d'œil aux sources de Django et je vois des fonctions comme ModelAdmin.changelist_view qui pourrait être inclus dans mon urls.py, mais je ne sais pas exactement comment cela fonctionnerait.

Mise à jour : J'ai trouvé une façon de faire ce que je veux (voir ci-dessous), mais j'aimerais connaître d'autres façons de procéder.

319voto

Paul Stone Points 1506

J'ai trouvé un moyen d'obtenir ce que je veux, en utilisant des modèles proxy pour contourner le fait que chaque modèle ne peut être enregistré qu'une seule fois.

class PostAdmin(admin.ModelAdmin):
    list_display = ('title', 'pubdate','user')

class MyPost(Post):
    class Meta:
        proxy = True

class MyPostAdmin(PostAdmin):
    def get_queryset(self, request):
        return self.model.objects.filter(user = request.user)

admin.site.register(Post, PostAdmin)
admin.site.register(MyPost, MyPostAdmin)

Ensuite, la valeur par défaut PostAdmin serait accessible à l'adresse suivante /admin/myapp/post et la liste des messages appartenant à l'utilisateur se trouverait à l'adresse /admin/myapp/myposts .

Après avoir examiné http://code.djangoproject.com/wiki/DynamicModels J'ai donc imaginé la fonction suivante pour faire la même chose :

def create_modeladmin(modeladmin, model, name = None):
    class  Meta:
        proxy = True
        app_label = model._meta.app_label

    attrs = {'__module__': '', 'Meta': Meta}

    newmodel = type(name, (model,), attrs)

    admin.site.register(newmodel, modeladmin)
    return modeladmin

Il peut être utilisé comme suit :

class MyPostAdmin(PostAdmin):
    def get_queryset(self, request):
        return self.model.objects.filter(user = request.user)

create_modeladmin(MyPostAdmin, name='my-posts', model=Post)

9 votes

Je ne savais pas qu'un modèle de proxy pouvait être enregistré dans le site d'administration. cela va beaucoup m'aider.

8 votes

J'ai également eu besoin d'enregistrer les mêmes modèles deux fois dans django admin et les modèles proxy semblent fonctionner. Mais j'ai trouvé un problème avec le système de permission. Voir ici : code.djangoproject.com/ticket/11154

4 votes

C'est aussi une bonne idée de changer le gestionnaire par défaut au lieu du queryset ModelAdmin. Ainsi, le comportement du modèle proxy est cohérent même en dehors de l'administrateur.

3voto

zzart Points 2162

La réponse de Paul Stone est absolument géniale ! Juste pour ajouter, pour Django 1.4.5 j'ai eu besoin d'hériter ma classe personnalisée de admin.ModelAdmin

class MyPostAdmin(admin.ModelAdmin):
    def queryset(self, request):
        return self.model.objects.filter(id=1)

0voto

Felipe Alcacibar Points 4822

Sur la base des réponses correctes, j'ai monkeypatché le fichier AdminSite et ajoutez la méthode register_via_proxy pour faciliter la tâche.

import re
from django.contrib import admin

def _register_proxy(self, model, admin_class):
    proxy_model = type(
        admin_class.__name__, (model,), {
            "__module__": re.sub(
                r'(^.*?)(\.[^\.]+)$', r'\1.proxy', model.__module__
            ),
            "Meta": type("Meta", tuple(), {
                "proxy": True,
                 "app_label": model._meta.app_label
            })
        }
    )

    return self.register(proxy_model, admin_class)

admin.sites.AdminSite.register_via_proxy = _register_proxy

Et l'utiliser, c'est comme :

site = admin.sites.AdminSite()
site.register_via_proxy(models.ModelType, AdminClass)

-1voto

Brandon H Points 2063

Il suffit d'utiliser un filtre de liste ou une hiérarchie de dates.

date_hierarchy = 'pub_date'

list_filter = ['pub_date',]

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