Кілька ModelAdmins / переглядів для тієї ж моделі в адміністраторі Django


150

Як я можу створити декілька ModelAdmin для однієї і тієї ж моделі, кожну з яких можна налаштувати по-різному і пов'язати з різними URL-адресами?

Скажімо, у мене є модель Джанго під назвою Posts. За замовчуванням у адміністраторському перегляді цієї моделі будуть перераховані всі об'єкти Пост.

Я знаю, що я можу налаштувати список об’єктів, що відображаються на сторінці різними способами, встановивши такі змінні, як list_display, або змінивши querysetметод у моєму ModelAdmin, як:

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)

За замовчуванням це буде доступне за URL-адресою /admin/myapp/post. Однак я хотів би мати кілька переглядів / ModelAdmins однієї моделі. наприклад /admin/myapp/post, перелічитиме всі об'єкти публікації та /admin/myapp/mypostsперелічить усі публікації, що належать користувачеві, а також /admin/myapp/draftpostперелічити всі публікації, які ще не були опубліковані. (це лише приклади, мої фактичні випадки використання складніші)

Ви не можете зареєструвати більше однієї моделі ModelAdmin для однієї моделі (це призводить до AlreadyRegisteredвиключення). В ідеалі я хотів би досягти цього, не вкладаючи все в один клас ModelAdmin і не записуючи власну функцію 'urls', щоб повернути інший набір запитів залежно від URL-адреси.

Я переглянув джерело Django і бачу такі функції, ModelAdmin.changelist_viewякі можна було б якось включити в мій urls.py, але я не впевнений, як саме це буде працювати.

Оновлення : я знайшов один із способів робити те, що я хочу (див. Нижче), але все одно хотів би почути інші способи цього.

Відповіді:


275

Я знайшов один із способів досягти того, що я хочу, використовуючи проксі-моделі, щоб обійти той факт, що кожна модель може бути зареєстрована лише один раз.

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)

Тоді за замовчуванням PostAdminбуде доступний /admin/myapp/postсписок, і перелік публікацій, які належать користувачеві, буде в /admin/myapp/myposts.

Переглянувши http://code.djangoproject.com/wiki/DynamicModels , я придумав таку функцію утиліти функції, щоб зробити те саме:

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

Це можна використовувати так:

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

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

8
Це круто. мені не було відомо, що на сайті адміністратора може бути зареєстрована модель проксі. це насправді дуже допоможе мені.
Брендон Генрі

8
Мені також потрібно було два рази зареєструвати одні і ті ж моделі в адміністраторі django, а проксі-моделі, здається, працюють. Але я знайшов одну проблему із системою дозволів. Дивіться тут: code.djangoproject.com/ticket/11154
bjunix

4
Також хороша ідея змінити менеджер за замовчуванням замість набору запитів ModelAdmin. Тож поведінка проксі-моделі узгоджується навіть поза адміністратором.
bjunix

4
Тепер справжня відповідь: чому django не дозволяє вам мати двох адміністраторів для однієї моделі? нам не потрібно хакнутись навколо речей лише за 2 рядки, які перевіряють це і видає помилку: s. Ще чудова відповідь!
Хассек

1
@zzart: є запит на вилучення, який, як видається, просто відсутні документи: github.com/django/django/pull/146/files
синій

3

Відповідь Пола Стоуна абсолютно чудова! Просто додам, для Django 1.4.5 мені потрібно було успадкувати свій власний клас відadmin.ModelAdmin

class MyPostAdmin(admin.ModelAdmin):
    def queryset(self, request):
        return self.model.objects.filter(id=1)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.