Mehrere ModelAdmins / Ansichten für dasselbe Modell in Django admin

149

Wie kann ich mehr als einen ModelAdmin für dasselbe Modell erstellen, die jeweils unterschiedlich angepasst und mit unterschiedlichen URLs verknüpft sind?

Angenommen, ich habe ein Django-Modell namens Posts. Standardmäßig listet die Administratoransicht dieses Modells alle Post-Objekte auf.

Ich weiß, dass ich die Liste der auf der Seite angezeigten Objekte auf verschiedene Arten anpassen kann, indem ich Variablen wie list_display einstelle oder die querysetMethode in meinem ModelAdmin wie folgt überschreibe :

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)

Standardmäßig ist dies über die URL zugänglich /admin/myapp/post. Ich möchte jedoch mehrere Ansichten / ModelAdmins desselben Modells haben. z. B. /admin/myapp/postwürde alle Beitragsobjekte auflisten und /admin/myapp/mypostswürde alle Beiträge auflisten, die dem Benutzer gehören, und /admin/myapp/draftpostkönnte alle Beiträge auflisten, die noch nicht veröffentlicht wurden. (Dies sind nur Beispiele, mein tatsächlicher Anwendungsfall ist komplexer)

Sie können nicht mehr als einen ModelAdmin für dasselbe Modell registrieren (dies führt zu einer AlreadyRegisteredAusnahme). Idealerweise möchte ich dies erreichen, ohne alles in eine einzelne ModelAdmin-Klasse zu packen und meine eigene URL-Funktion zu schreiben, um abhängig von der URL einen anderen Abfragesatz zurückzugeben.

Ich habe mir die Django-Quelle angesehen und sehe, ModelAdmin.changelist_viewdass solche Funktionen irgendwie in meiner urls.py enthalten sein könnten, aber ich bin mir nicht sicher, wie das genau funktionieren würde.

Update : Ich habe einen Weg gefunden, um das zu tun, was ich will (siehe unten), aber ich würde immer noch gerne andere Wege hören, dies zu tun.

Paul Stone
quelle

Antworten:

274

Ich habe einen Weg gefunden, um das zu erreichen, was ich will, indem ich Proxy-Modelle verwende, um die Tatsache zu umgehen, dass jedes Modell möglicherweise nur einmal registriert wird.

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)

Dann wäre die Standardeinstellung PostAdminunter verfügbar /admin/myapp/postund die Liste der Beiträge des Benutzers wäre unter /admin/myapp/myposts.

Nachdem ich mir http://code.djangoproject.com/wiki/DynamicModels angesehen habe , habe ich mir das folgende Funktionsdienstprogramm ausgedacht, um dasselbe zu tun:

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

Dies kann wie folgt verwendet werden:

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
quelle
8
das ist fantastisch. Mir war nicht bewusst, dass ein Proxy-Modell auf der Admin-Site registriert werden konnte. das wird mir tatsächlich sehr helfen.
Brandon Henry
8
Ich musste auch die gleichen Modelle zweimal in Django Admin registrieren und Proxy-Modelle scheinen zu funktionieren. Aber ich habe ein Problem mit dem Berechtigungssystem gefunden. Siehe hier: code.djangoproject.com/ticket/11154
bjunix
4
Es ist auch eine gute Idee, den Standardmanager anstelle des ModelAdmin-Abfragesatzes zu ändern. Das Verhalten des Proxy-Modells ist also auch außerhalb des Administrators konsistent.
Bjunix
4
Die eigentliche Antwort lautet nun: Warum lässt Django Sie nicht zwei Administratoren für dasselbe Modell haben? Wir sollten nicht für nur 2 Zeilen herumhacken müssen, die das überprüfen und einen Fehler auslösen: s. Tolle Antwort noch!
Hassek
1
@zzart: Es gibt eine ausstehende Pull-Anfrage, bei der anscheinend nur Dokumente fehlen: github.com/django/django/pull/146/files
blueyed
3

Die Antwort von Paul Stone ist absolut großartig! Nur um hinzuzufügen, für Django 1.4.5 musste ich meine benutzerdefinierte Klasse von erbenadmin.ModelAdmin

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