Wiele modeli / widoków ModelAdmins dla tego samego modelu w panelu administracyjnym Django

150

Jak mogę utworzyć więcej niż jednego ModelAdmin dla tego samego modelu, każdy dostosowany w inny sposób i połączony z różnymi adresami URL?

Powiedzmy, że mam model Django o nazwie Posty. Domyślnie widok administratora tego modelu zawiera listę wszystkich obiektów Post.

Wiem, że mogę dostosować listę obiektów wyświetlanych na stronie na różne sposoby, ustawiając zmienne, takie jak list_display lub zastępując querysetmetodę w moim ModelAdmin w następujący sposób:

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)

Domyślnie byłoby to dostępne pod adresem URL /admin/myapp/post. Chciałbym jednak mieć wiele widoków / ModelAdmins tego samego modelu. np. wyświetli /admin/myapp/postlistę wszystkich obiektów postów i /admin/myapp/mypostswyświetli wszystkie posty należące do użytkownika i /admin/myapp/draftpostmoże wyświetlić wszystkie posty, które nie zostały jeszcze opublikowane. (to tylko przykłady, mój rzeczywisty przypadek użycia jest bardziej złożony)

Nie można zarejestrować więcej niż jednego ModelAdmin dla tego samego modelu (powoduje to AlreadyRegisteredwyjątek). Idealnie chciałbym to osiągnąć bez umieszczania wszystkiego w jednej klasie ModelAdmin i pisania własnej funkcji „urls”, która zwraca inny zestaw zapytań w zależności od adresu URL.

Rzuciłem okiem na źródło Django i widzę, ModelAdmin.changelist_viewże takie funkcje mogą być w jakiś sposób zawarte w moim urls.py, ale nie jestem pewien, jak to dokładnie działałoby.

Aktualizacja : znalazłem jeden sposób robienia tego, co chcę (patrz poniżej), ale nadal chciałbym usłyszeć, jak to zrobić.

Paul Stone
źródło

Odpowiedzi:

275

Znalazłem jeden sposób, aby osiągnąć to, czego chcę, używając modeli proxy, aby ominąć fakt, że każdy model może być zarejestrowany tylko raz.

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)

Wtedy domyślny PostAdminbyłby dostępny pod adresem, /admin/myapp/posta lista postów posiadanych przez użytkownika byłaby pod adresem /admin/myapp/myposts.

Po obejrzeniu http://code.djangoproject.com/wiki/DynamicModels wymyśliłem następującą funkcję narzędzia, aby zrobić to samo:

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

Można to wykorzystać w następujący sposób:

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
źródło
8
to jest niesamowite. Nie wiedziałem, że model proxy można zarejestrować w serwisie administratora. to naprawdę bardzo mi pomoże.
Brandon Henry
8
Musiałem również dwukrotnie zarejestrować te same modele w django admin i modele proxy wydają się działać. Ale znalazłem jeden problem z systemem uprawnień. Zobacz tutaj: code.djangoproject.com/ticket/11154
bjunix
4
Dobrym pomysłem jest również zmiana domyślnego menedżera zamiast zestawu zapytań ModelAdmin. Tak więc zachowanie modelu proxy jest spójne nawet poza administratorem.
bjunix
4
Teraz prawdziwa odpowiedź brzmi: dlaczego django nie pozwala ci mieć dwóch administratorów dla tego samego modelu? nie powinniśmy potrzebować tylko dwóch wierszy, które sprawdzają to i generują błąd: s. Nadal świetna odpowiedź!
Hassek
1
@zzart: jest oczekujące żądanie ściągnięcia, które wydaje się po prostu brakować dokumentów: github.com/django/django/pull/146/files
blueyed
3

Odpowiedź Paula Stone'a jest absolutnie świetna! Dodam, że dla Django 1.4.5 musiałem odziedziczyć moją klasę niestandardową zadmin.ModelAdmin

class MyPostAdmin(admin.ModelAdmin):
    def queryset(self, request):
        return self.model.objects.filter(id=1)
zzart
źródło