Действия администрации ¶
Вкратце основной способ работы в администрировании Django: «выберите объект, затем измените его». Он хорошо работает в большинстве случаев использования. Однако, если вам нужно внести одно и то же изменение в несколько объектов одновременно, этот способ работы может быть довольно утомительным.
В этих случаях администрация Django позволяет вам писать и регистрировать «действия» - функции, вызываемые со списком объектов, выбранных на странице списка для модификации.
Если вы посмотрите на любой список объектов для редактирования в админке, вы увидите эту функцию в действии; В Django есть действие «удалить выбранные объекты», доступное для всех моделей. Например, вот пользовательский модуль для приложения, django.contrib.auth
встроенного в Django:

Предупреждение
Действие «удалить выбранные объекты» используется QuerySet.delete()
из соображений эффективности, что приводит к важному предупреждению: delete()
ваш метод моделей не будет вызываться.
Если вы хотите изменить это поведение, вы можете переопределить ModelAdmin.delete_queryset()
или написать настраиваемое действие, которое позаботится об удалении по-своему - например, вызов Model.delete()
каждого из выбранных элементов.
Дополнительную информацию о массовом удалении см. В документации по удалению объектов .
Читайте дальше, чтобы узнать, как добавить свои акции в этот список.
Написание действий ¶
Лучший способ объяснить действия - показать пример. Пошли!
Распространенным вариантом использования административных действий является массовое обновление шаблона. Представьте себе новостное приложение с шаблоном Article
:
from django.db import models
STATUS_CHOICES = [
('d', 'Draft'),
('p', 'Published'),
('w', 'Withdrawn'),
]
class Article(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
status = models.CharField(max_length=1, choices=STATUS_CHOICES)
def __str__(self):
return self.title
Обычная задача, которую мы могли бы выполнить с помощью такого шаблона, - это обновить статус статьи с «черновика» до «опубликована». Мы могли бы легко сделать это в администрировании, по одной статье за раз, но если мы захотим опубликовать серию статей массово, это будет утомительно. Итак, давайте напишем действие, которое позволяет нам изменить статус статьи на «опубликована».
Написание функций действий ¶
Во-первых, нам нужно написать функцию, которая вызывается, когда действие запускается администрацией. Функции действий - это обычные функции, которые принимают три параметра:
ModelAdmin
Заинтересованный класс- Объект,
HttpRequest
представляющий текущий запрос - Набор запросов,
QuerySet
содержащий все объекты, выбранные пользователем.
Нашей функции публикации статьи не понадобится класс ModelAdmin
или объект запроса, но мы будем использовать набор запросов:
def make_published(modeladmin, request, queryset):
queryset.update(status='p')
Заметка
Для повышения производительности мы будем использовать метод обновления набора запросов. Другие типы действий могут потребовать индивидуального управления каждым объектом; в этом случае мы будем перебирать набор запросов:
for obj in queryset:
do_something_with(obj)
На самом деле это все, что нужно написать для действия! Однако мы собираемся предпринять необязательный, но полезный дополнительный шаг и присвоить действию «красивый» заголовок в интерфейсе администратора. По умолчанию это действие отображается в списке действий как «Опубликовать» - имя функции с подчеркиванием заменено пробелами. Это нормально, но мы можем предоставить более удобное и удобное имя, присвоив функции make_published
атрибут short_description
:
def make_published(modeladmin, request, queryset):
queryset.update(status='p')
make_published.short_description = "Mark selected stories as published"
Заметка
Это может показаться знакомым; опция администрирования list_display
также использует тот же метод для предоставления удобочитаемых описаний для перечисленных там функций обратного вызова.
Добавление действий в класс ¶ModelAdmin
Затем необходимо будет сообщить ModelAdmin
о действии. Он работает как любой другой вариант конфигурации. Таким образом, admin.py
полный файл с действием и его регистрацией будет выглядеть так:
from django.contrib import admin
from myapp.models import Article
def make_published(modeladmin, request, queryset):
queryset.update(status='p')
make_published.short_description = "Mark selected stories as published"
class ArticleAdmin(admin.ModelAdmin):
list_display = ['title', 'status']
ordering = ['title']
actions = [make_published]
admin.site.register(Article, ArticleAdmin)
С помощью этого кода список объектов, которые нужно изменить в интерфейсе администрирования, выглядит следующим образом:

Вот и все, что нужно сделать! Если вы умираете от желания написать свои собственные действия, теперь вы знаете достаточно, чтобы начать. Остальная часть этого документа охватывает более сложные методы.
Обработка ошибок в действиях ¶
Если есть какие-либо предсказуемые условия ошибки, которые могут возникнуть при выполнении вашего действия, вы должны исправить это, уведомив пользователя о проблеме. Это означает обработку исключений и использование django.contrib.admin.ModelAdmin.message_user()
для отображения понятного описания проблемы в ответе.
Продвинутые техники действий ¶
Есть еще несколько опций и возможностей, которые вы можете использовать для более продвинутых опций.
Действия как методы ¶ModelAdmin
В приведенном выше примере показано действие, make_published
определенное как функция. Это абсолютно правильно, но не идеально с точки зрения дизайна кода: поскольку действие тесно связано с объектом Article
, имеет смысл объединить действие с ArticleAdmin
самим объектом . ,
Вы можете сделать это так
class ArticleAdmin(admin.ModelAdmin):
...
actions = ['make_published']
def make_published(self, request, queryset):
queryset.update(status='p')
make_published.short_description = "Mark selected stories as published"
Обратите внимание , первое , что мы преобразовали make_published
в метод и переименован параметр modeladmin
в self
, то мы помещаем строку make_published
в actions
вместо прямой ссылки на функцию. Это говорит, что ModelAdmin
нужно найти действие как метод.
Определение действий как методов дает действию более идиоматический доступ к ModelAdmin
самому классу , позволяя действию вызывать любой из методов, определенных приложением администрирования.
Например, мы можем использовать self
для отображения сообщения пользователю, информирующего его об успешном выполнении действия:
from django.contrib import messages
from django.utils.translation import ngettext
class ArticleAdmin(admin.ModelAdmin):
...
def make_published(self, request, queryset):
updated = queryset.update(status='p')
self.message_user(request, ngettext(
'%d story was successfully marked as published.',
'%d stories were successfully marked as published.',
updated,
) % updated, messages.SUCCESS)
Это делает действие похожим на то, что делает сама администрация после успешного выполнения действия:

Действия, которые предоставляют промежуточные страницы ¶
По умолчанию после выполнения действия пользователь перенаправляется на исходную страницу списка редактирования. Однако некоторые действия, особенно более сложные, могут потребовать ссылки на промежуточные страницы. Например, встроенное действие удаления запрашивает подтверждение перед удалением выбранных объектов.
Чтобы предоставить промежуточную страницу, верните ответ HttpResponse
(или подкласс) своего действия. Например, вы можете написать функцию экспорта, которая использует функции сериализации Django для экспорта определенных выбранных объектов как JSON:
from django.core import serializers
from django.http import HttpResponse
def export_as_json(modeladmin, request, queryset):
response = HttpResponse(content_type="application/json")
serializers.serialize("json", queryset, stream=response)
return response
В общем, приведенный выше пример не считается хорошей идеей. В большинстве случаев лучше всего вернуть ответ HttpResponseRedirect
и перенаправить пользователя в созданное вами представление, передав список выбранных объектов в строке запроса GET. Это позволяет обеспечить сложную логику взаимодействия на промежуточных страницах. Например, если вы хотите предоставить более полную функцию экспорта, вы хотите, чтобы пользователь мог выбирать формат и, возможно, список полей для включения в экспорт. Лучше всего было бы написать небольшое действие, которое перенаправляет на настраиваемое представление экспорта:
from django.contrib.contenttypes.models import ContentType
from django.http import HttpResponseRedirect
def export_selected_objects(modeladmin, request, queryset):
selected = queryset.values_list('pk', flat=True)
ct = ContentType.objects.get_for_model(queryset.model)
return HttpResponseRedirect('/export/?ct=%s&ids=%s' % (
ct.pk,
','.join(str(pk) for pk in selected),
))
Как видите, действие довольно краткое; вся сложная логика делегируется виду экспорта. Он должен отвечать за обработку объектов любого типа, отсюда и наличие модели ContentType
.
Написание этой точки зрения предоставляется читателю на усмотрение.
Действия доступны для всего сайта ¶
-
AdminSite.
add_action
( действие , имя = Нет ) ¶ Некоторые действия более эффективны, если они доступны для всех объектов на сайте администрирования - действие экспорта, определенное выше, было бы хорошим кандидатом. Вы можете сделать действие глобально доступным, используя
AdminSite.add_action()
. Например :from django.contrib import admin admin.site.add_action(export_selected_objects)
Это делает действие
export_selected_objects
глобально доступным как действие с именем «export_selected_objects». Вы можете явно дать действию имя - полезно, если позже вы захотите программно удалить действие, - передав второй аргумент вAdminSite.add_action()
admin.site.add_action(export_selected_objects, 'export_selected')
Отключение действий ¶
Иногда вам нужно отключить определенные действия - особенно те, которые записаны глобально - для определенных объектов. Есть несколько способов отключить действия:
Отключение действия на уровне сайта ¶
-
AdminSite.
disable_action
( имя ) ¶ Если вам нужно отключить действие на всем сайте, вы можете позвонить
AdminSite.disable_action()
.Например, вы можете использовать этот метод для удаления встроенного действия «удалить выбранные объекты»:
admin.site.disable_action('delete_selected')
После того, как вы сделаете вышеуказанное, это действие больше не будет доступно для всего сайта.
Если, однако, вам нужно повторно активировать действие, которое глобально отключено для конкретной модели, все, что вам нужно сделать, это явно указать его в списке
ModelAdmin.actions
:# Globally disable delete selected admin.site.disable_action('delete_selected') # This ModelAdmin will not have delete_selected available class SomeModelAdmin(admin.ModelAdmin): actions = ['some_other_action'] ... # This one will class AnotherModelAdmin(admin.ModelAdmin): actions = ['delete_selected', 'a_third_action'] ...
Отключение всех действий для ModelAdmin
определенного класса ¶
Если вы не хотите, чтобы для данного класса были доступны какие-либо массовые действия ModelAdmin
, установите ModelAdmin.actions
значение None
:
class MyModelAdmin(admin.ModelAdmin):
actions = None
Это указывает классу ModelAdmin
не просматривать и не разрешать какие-либо действия, включая действия на уровне сайта .
Условная активация или деактивация действий ¶
-
ModelAdmin.
get_actions
( запрос ) ¶ Наконец, вы можете условно активировать или деактивировать действия в соответствии с запросом (и, следовательно, пользователем), переопределив
ModelAdmin.get_actions()
.Это возвращает словарь разрешенных действий. Ключи - это имена действий, а значения - это кортежи .
(fonction, nom, description courte)
Например, если вы хотите, чтобы только пользователи, чьи фамилии начинаются с "J", могли удалять объекты массово
class MyModelAdmin(admin.ModelAdmin): ... def get_actions(self, request): actions = super().get_actions(request) if request.user.username[0].upper() != 'J': if 'delete_selected' in actions: del actions['delete_selected'] return actions
Настройка разрешений для действий ¶
Действия могут ограничить их доступность для пользователей с определенными разрешениями, установив атрибут allowed_permissions
в функции действия.
def make_published(modeladmin, request, queryset):
queryset.update(status='p')
make_published.allowed_permissions = ('change',)
Действие make_published()
будет доступно только тем пользователям, которые передали управление ModelAdmin.has_change_permission()
.
Если allowed_permissions
у вас более одного разрешения, действие будет доступно, если пользователь передаст хотя бы один из элементов управления.
Доступные значения allowed_permissions
и соответствующие им методы контроля:
'add'
(Дополнительно):ModelAdmin.has_add_permission()
'change'
(Модификация):ModelAdmin.has_change_permission()
'delete'
(Удаление):ModelAdmin.has_delete_permission()
'view'
(Дисплей):ModelAdmin.has_view_permission()
Вы можете указать другие значения, если вы реализуете соответствующий метод для соответствующего класса .has_<valeur>_permission(self, request)
ModelAdmin
Например :
from django.contrib import admin
from django.contrib.auth import get_permission_codename
class ArticleAdmin(admin.ModelAdmin):
actions = ['make_published']
def make_published(self, request, queryset):
queryset.update(status='p')
make_published.allowed_permissions = ('publish',)
def has_publish_permission(self, request):
"""Does the user have the publish permission?"""
opts = self.opts
codename = get_permission_codename('publish', opts)
return request.user.has_perm('%s.%s' % (opts.app_label, codename))