Несколько ModelAdmins / представлений для одной и той же модели в админке Django

151

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

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

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

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

Пол Стоун
источник

Ответы:

277

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

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)
zzart
источник