Не так давно, в джанго-админке появились Admin Actions (http://docs.djangoproject.com/en/dev/ref/contrib/admin/actions/#ref-contrib-admin-actions). О них я и хотел бы сегодня рассказать. В процессе записи такие действия я буду называть AdminAction.
Что это, и зачем оно мне нужно?
На самом деле необходимость такой вещи назрела уже давно. Допустим я хочу удалить все объекты определенной модели из админки (представим, что у меня их ~100 штук), не имея доступа к базе данных. Задача превращается в довольно муторную, и во всех нормальных продуктах давно уже можно пару раз жмакнуть по галочке "Выделить все" и удалить все выделенное за следующие пару кликов. Поэтому выкручивались джангисты как могли. А теперь все просто.Смотрим как это просто
AdminAction это обычная функция, которая принимает три аргумента.- Экземпляр ModelAdmin, к которому прикручено действие.
- HttpRequest объект, пришедший от пользователя.
- QuerySet выделенных объектов.
class Post(models.Model):Boolean-поле is_draft сигнализирует о том, что запись черновик, и публиковать ее смысла нет. Сделаем свой AdminAction, который будет публиковать выделенные посты, т.е. ставить у постов is_draft=False.
""" Post model. """
title = models.CharField(max_length=25)
content = models.TextField()
is_draft = models.BooleanField(default=True)
def __unicode__(self): return self.title
Открываем admin.py и приводим его к такому виду:
from django.contrib import admin
from testapp.models import Post
def make_published(modeladmin, request, queryset):
""" Make all posts published. """
queryset.update(is_draft=False)
make_published.short_description = "Mark selected posts as published"
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'is_draft')
actions = [make_published]
admin.site.register(Post, PostAdmin)
Что мы тут видим. Видим функцию make_published которая как-раз принимает те три аргумента о которых я писал выше. В PostAdmin видим строчку actions = [make_published]. Эта строчка подключает наш AdminAction к PostAdmin. Внутри функции make_published мы просто вызываем метод update у QuerySet и устанавливаем для всех выделенных объектов is_draft=False. Вот и все. Запускаем приложение и смотрим как это работает:
Логичнее было-бы, плодить новые функции внутри класса PostAdmin, и не выносить их наружу, т.к. больше они нигде не используются. Это возможно, просто перепишем наш пример следующим образом:
from django.contrib import admin
from testapp.models import Post
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'is_draft')
actions = ['make_published']
def make_published(self, request, queryset):
""" Make all posts published. """
queryset.update(is_draft=False)
make_published.short_description = "Mark selected posts as published"
admin.site.register(Post, PostAdmin)
Что изменилось? Ну во-первых функция make_published перекочевала в PostAdmin. Во-вторых вместо первого аргумента теперь self. И в третьих в actions она указана строкой. Запускаем, и проверяем, что все работает.
Необходимые вещи
Логично было бы показывать пользователю, сколько постов реально было опубликовано при действии. Для этого мы воспользуемся методом ModelAdmin.message_user(request, message).Пишем:
from django.contrib import admin
from testapp.models import Post
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'is_draft')
actions = ['make_published']
def make_published(self, request, queryset):
""" Make all posts published. """
count = queryset.filter(is_draft=True).update(is_draft=False)
self.message_user(request, '%s posts mark as published.' % count)
make_published.short_description = "Mark selected posts as published"
admin.site.register(Post, PostAdmin)
Проверяем:
Отлично. Все работает как нужно.
Интересные возможности
Помимо рассмотренного выше, есть и другие возможности, для гибкой настройки административного интерфейса.AdminAction может возвращать объект типа HttpResponse, который будет отдан напрямую пользователю. Используя это мы можем делать экспорт моделей, сериализацию выбранных объектов в JSON, предпросмотр нескольких объектов, и вообще, все что придет нам в голову.
Включаем, выключаем
Мы рассмотрели возможность подключения AdminAction к определенному ModelAdmin. Но как могли заметить, стандартное действие удаляющее выделенные объекты, никуда при этом не делось. А что, если нам не нравится стандартный AdminAction, который позволяет удалять выделенные объекты? Это не проблема - AdminAction's можно активировать и деактивировать для всего сайта в целом. Например, чтобы выключить тот самый delete_selected, мы должны написать в admin.py:admin.site.disable_action('delete_selected')После этого, мы можем включить действие delete_selected там, где оно нужно, просто указав в списке actions у определенного ModelAdmin. А чтобы активировать наше действие, например - make_all_good для всего сайта в целом, достаточно написать:
admin.site.add_action(make_all_good, 'make_good_selected')
Второй аргумент - не обязателен. Просто используя его мы сможем потом также отключить наше действие, как выше отключили delete_selected.
Чтобы выключить все действия для определенной ModelAdmin, достаточно присвоить action=None, внутри класса.
А если мы захотим иметь разный набор действий в зависимости от каких-либо условий, например от группы пользователя, то нам достаточно переопределить метод ModelAdmin.get_actions(self, request). Который возвращает список actions.
На мой взгляд - меганужная и ожидаемая фича.
Комментариев нет:
Отправить комментарий