Несколько ModelAdmins/views для той же модели в Django admin

Как я могу создать более одного ModelAdmin для одной и той же модели, каждый из которых настроен по-разному и связан с разными URL-адресами?

Скажем, у меня есть модель Django, называемая Posts. По умолчанию в представлении администратора этой модели будут перечислены все объекты Post.

Я знаю, что могу настроить список объектов, отображаемых на странице различными способами, задав переменные типа 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 той же модели. e.g /admin/myapp/post будет перечислять все объекты post, а /admin/myapp/myposts будет перечислять все записи, принадлежащие пользователю, а /admin/myapp/draftpost может отображать все опубликованные сообщения. (это всего лишь примеры, мой фактический прецедент более сложный)

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

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

Обновление. Я нашел один способ сделать то, что хочу (см. ниже), но мне все же хотелось бы услышать другие способы сделать это.

Ответ 1

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

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)

Ответ 2

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

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

Ответ 3

просто используйте list_filter или date_hierarchy.

date_hierarchy = 'pub_date'

list_filter = ['pub_date',]