Plusieurs ModelAdmins / vues pour le même modèle dans l'admin Django

150

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 répertorie tous les objets Post.

Je sais que je peux personnaliser la liste des objets affichés sur la page de différentes manières en définissant des variables telles que list_display ou en remplaçant la querysetméthode dans mon ModelAdmin comme ceci:

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, cela serait accessible à l'URL /admin/myapp/post. Cependant, je voudrais avoir plusieurs vues / ModelAdmins du même modèle. par exemple /admin/myapp/post, listerait tous les objets de publication, /admin/myapp/mypostslisterait tous les messages appartenant à l'utilisateur, et /admin/myapp/draftpostpourrait lister tous les messages qui n'ont pas encore été publiés. (ce ne sont que des exemples, mon cas d'utilisation actuel est plus complexe)

Vous ne pouvez pas enregistrer plus d'un ModelAdmin pour le même modèle (cela entraîne une AlreadyRegisteredexception). Idéalement, j'aimerais y parvenir sans tout mettre dans une seule classe ModelAdmin et sans écrire ma propre fonction `` urls '' pour renvoyer un ensemble de requêtes différent en fonction de l'URL.

J'ai jeté un coup d'œil à la source Django et je vois des fonctions comme ModelAdmin.changelist_viewcelle-là qui pourraient d'une manière ou d'une autre être incluses dans mon urls.py, mais je ne sais pas exactement comment cela fonctionnerait.

Mise à jour : j'ai trouvé un moyen de faire ce que je veux (voir ci-dessous), mais j'aimerais toujours entendre d'autres façons de le faire.

Paul Stone
la source

Réponses:

276

J'ai trouvé un moyen d'atteindre 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 PostAdminserait accessible à /admin/myapp/postet la liste des publications appartenant à l'utilisateur serait à /admin/myapp/myposts.

Après avoir consulté http://code.djangoproject.com/wiki/DynamicModels , j'ai proposé la fonction utilitaire de 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

Cela 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)
Paul Stone
la source
8
C'est génial. je ne savais pas qu'un modèle de proxy pouvait être enregistré sur le site d'administration. cela m'aidera grandement.
Brandon Henry
8
J'avais également besoin d'enregistrer les mêmes modèles deux fois dans l'admin django et les modèles de proxy semblent fonctionner. Mais j'ai trouvé un problème avec le système d'autorisation. Voir ici: code.djangoproject.com/ticket/11154
bjunix
4
C'est également une bonne idée de changer le gestionnaire par défaut au lieu du jeu de requêtes ModelAdmin. Le comportement du modèle proxy est donc cohérent même en dehors de l'administrateur.
bjunix
4
Maintenant, la vraie réponse est, pourquoi django ne vous permet pas d'avoir deux administrateurs pour le même modèle? nous ne devrions pas avoir besoin de pirater les choses pour seulement 2 lignes qui vérifient cela et génèrent une erreur: s. Excellente réponse encore!
Hassek
1
@zzart: il y a une demande d'extraction en attente, qui semble manquer de documentation: github.com/django/django/pull/146/files
blueyed
3

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

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