Beberapa ModelAdmins / tampilan untuk model yang sama di Django admin

150

Bagaimana saya bisa membuat lebih dari satu ModelAdmin untuk model yang sama, masing-masing disesuaikan secara berbeda dan ditautkan ke URL yang berbeda?

Katakanlah saya memiliki model Django yang disebut Posting. Secara default, tampilan admin model ini akan mencantumkan semua objek Posting.

Saya tahu saya dapat mengkustomisasi daftar objek yang ditampilkan pada halaman dalam berbagai cara dengan mengatur variabel seperti list_display atau mengganti querysetmetode dalam ModelAdmin saya seperti:

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)

Secara default, ini dapat diakses di URL /admin/myapp/post. Namun saya ingin memiliki beberapa tampilan / ModelAdmins dari model yang sama. misalnya /admin/myapp/postakan mendaftar semua objek posting, dan /admin/myapp/mypostsakan mendaftar semua posting milik pengguna, dan /admin/myapp/draftpostmungkin daftar semua posting yang belum dipublikasikan. (Ini hanya contoh, kasus penggunaan saya yang sebenarnya lebih kompleks)

Anda tidak dapat mendaftarkan lebih dari satu ModelAdmin untuk model yang sama (ini menghasilkan AlreadyRegisteredpengecualian). Idealnya saya ingin mencapai ini tanpa meletakkan semuanya menjadi satu kelas ModelAdmin tunggal dan menulis fungsi 'url' saya sendiri untuk mengembalikan queryset yang berbeda tergantung pada URL.

Saya telah melihat sumber Django dan saya melihat fungsi-fungsi seperti ModelAdmin.changelist_viewitu bisa dimasukkan ke dalam urls.py saya, tetapi saya tidak yakin bagaimana cara kerjanya.

Pembaruan : Saya telah menemukan satu cara untuk melakukan apa yang saya inginkan (lihat di bawah), tetapi saya masih ingin mendengar cara lain untuk melakukan ini.

Paul Stone
sumber

Jawaban:

275

Saya telah menemukan satu cara untuk mencapai apa yang saya inginkan, dengan menggunakan model proksi untuk menyiasati fakta bahwa masing-masing model dapat didaftarkan hanya satu kali.

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)

Maka default PostAdminakan dapat diakses di /admin/myapp/postdan daftar posting yang dimiliki oleh pengguna akan berada di /admin/myapp/myposts.

Setelah melihat http://code.djangoproject.com/wiki/DynamicModels , saya membuat fungsi utilitas fungsi berikut untuk melakukan hal yang sama:

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

Ini dapat digunakan sebagai berikut:

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
sumber
8
ini luar biasa. saya tidak tahu bahwa model proxy dapat didaftarkan di situs admin. ini benar-benar akan sangat membantu saya.
Brandon Henry
8
Saya juga perlu mendaftarkan model yang sama dua kali di admin Django dan model proxy tampaknya berfungsi. Tetapi saya menemukan satu masalah dengan sistem izin. Lihat di sini: code.djangoproject.com/ticket/11154
bjunix
4
Ini juga merupakan ide yang baik untuk mengubah manajer default daripada queryset ModelAdmin. Jadi perilaku model proxy konsisten bahkan di luar admin.
bjunix
4
Sekarang jawaban sebenarnya adalah, mengapa Django tidak membiarkan Anda memiliki dua admin untuk model yang sama? kita tidak perlu meretas sekitar hanya untuk 2 baris yang memeriksa itu dan melemparkan kesalahan: s. Jawaban yang bagus!
Hassek
1
@zzart: ada permintaan tunda yang tertunda, yang tampaknya hanya ada dokumen yang hilang: github.com/django/django/pull/146/files
blueyed
3

Jawaban Paul Stone benar-benar hebat! Sebagai tambahan, untuk Django 1.4.5 saya perlu mewarisi kelas khusus sayaadmin.ModelAdmin

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