Сегодня мы займёмся настоящей магией – создадим свои действия (actions) для массового управления объектами в админке. Что такое действия (actions) в Django Admin? Давайте представим, что вы управляете огромным списком пользователей. Теперь предположим, что вам нужно удалить или изменить сразу N объектов (например, активировать пользователей или перевести их в группу "VIP"). Конечно, можно открыть каждый объект и редактировать его вручную, но зачем, если мы можем применить действие сразу ко всем выбранным объектам? Вот тут-то и вступает в игру функционал actions.
Действия (actions) в Django Admin – это кастомные функции, которые вы можете выполнить над одним или несколькими объектами. Они добавляются в выпадающий список над списком объектов.
Пример выпадающего списка с действиями вы наверняка видели:
- "Удалить выбранные объекты" – это встроенное действие.
- А мы научимся добавлять свои, кастомные действия.
Как работают действия в Django Admin?
Действия связаны с классом ModelAdmin. Они регистрируются в специальном атрибуте actions этого класса. Действия принимают три параметра:
modeladmin– текущий экземплярModelAdmin.request– HTTP-запрос.queryset– набор объектов, над которыми нужно выполнить действие.
По сути, действие – это обычная функция, которую вы добавляете в админ-зону. А теперь разберёмся с этим на практике.
Основы создания действий
Давайте добавим первое пользовательское действие в админке. Для примера, предположим, что у нас есть модель User, а в ней есть поле is_active, и мы хотим массово активировать пользователей.
# admin.py
from django.contrib import admin
from .models import User
@admin.action(description='Активировать выбранных пользователей')
def activate_users(modeladmin, request, queryset):
"""Действие для активации пользователей"""
queryset.update(is_active=True)
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ('username', 'email', 'is_active')
actions = [activate_users]
🖥 Что здесь происходит?
- Мы создали функцию
activate_users, которая принимаетquerysetи обновляет полеis_activeдля всех выбранных пользователей. - Использовали декоратор
@admin.action, чтобы задать описание действия, которое будет отображаться в выпадающем списке. - Добавили это действие в список
actionsвашегоUserAdmin.
Теперь зайдите в админ-зону, выберите несколько пользователей, выберите действие "Активировать выбранных пользователей" и нажмите "Применить". Voilà! Ваши пользователи активированы.
Безопасное удаление: запрос подтверждения действий
Иногда действия могут быть опасными (удаление данных, например), и лучше попросить администратора подтвердить своё намерение. Django позволяет это сделать, бросив исключение django.contrib.admin.ModelAdmin.message_user.
Пример: добавим действие для массового удаления, но сначала попросим подтвердить.
# admin.py
from django.contrib import admin
from django.contrib import messages
from .models import User
@admin.action(description='Удалить выбранных пользователей (подтверждение)')
def delete_users_with_confirmation(modeladmin, request, queryset):
if 'confirm' in request.POST:
# Если подтверждение получено, удаляем
count = queryset.count()
queryset.delete()
modeladmin.message_user(request, f'{count} пользователей были удалены.', messages.SUCCESS)
else:
# Иначе показываем предупреждение
modeladmin.message_user(
request,
"Вы планируете удалить выбранных пользователей. Нажмите 'Применить' ещё раз для подтверждения.",
messages.WARNING
)
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
actions = [delete_users_with_confirmation]
Как это работает?
- При первом вызове действия мы отправляем администратору предупреждение (через
message_user). - Если администратор повторяет действие (проверяем по наличию
'confirm'вrequest.POST), данные удаляются.
Использование внешних данных в действиях
Теперь представим задачу: вы хотите отправить email всем выбранным пользователям. Это немного сложнее, ведь нам нужно взаимодействовать с внешними сервисами.
Пример:
# admin.py
from django.core.mail import send_mail
@admin.action(description='Отправить приветственное письмо выбранным пользователям')
def send_welcome_email(modeladmin, request, queryset):
for user in queryset:
send_mail(
subject='Добро пожаловать!',
message='Спасибо за регистрацию на нашем сайте.',
from_email='admin@example.com',
recipient_list=[user.email],
fail_silently=True, # Не пугайте администратора ошибками :D
)
modeladmin.message_user(request, f'Письма отправлены {queryset.count()} пользователям.', messages.INFO)
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
actions = [send_welcome_email]
Группировка объектов по категориям
А как насчёт того, чтобы изменить поведение действия в зависимости от содержимого queryset? Например, вы хотите активировать только тех пользователей, которые зарегистрировались более 30 дней назад.
Пример:
from datetime import timedelta
from django.utils.timezone import now
@admin.action(description="Активировать старых пользователей")
def activate_old_users(modeladmin, request, queryset):
threshold = now() - timedelta(days=30)
old_users = queryset.filter(date_joined__lt=threshold)
count = old_users.update(is_active=True)
modeladmin.message_user(request, f'{count} старых пользователей были активированы.', messages.SUCCESS)
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
actions = [activate_old_users]
Теперь только те пользователи, которые зарегистрировались давно (более 30 дней назад), будут активированы.
Ограничение доступности действий
Иногда вам может понадобиться ограничить доступ к действию определённым категориям пользователей или объектам. Например, вы не хотите, чтобы действие было доступно для суперпользователей или для объектов, которые уже активированы.
Пример:
@admin.action(description='Деактивировать выбранных пользователей')
def deactivate_users(modeladmin, request, queryset):
queryset.update(is_active=False)
class UserAdmin(admin.ModelAdmin):
actions = [deactivate_users]
def get_actions(self, request):
actions = super().get_actions(request)
# Убрать действие для суперпользователей
if request.user.is_superuser:
if 'deactivate_users' in actions:
del actions['deactivate_users']
return actions
admin.site.register(User, UserAdmin)
Отображение результата действий
Когда действие выполнено, важно оповестить администратора о результате. Django предоставляет метод message_user, который мы уже использовали ранее. Вот основные типы сообщений:
- messages.SUCCESS – для успешных операций.
- messages.INFO – для информационных сообщений.
- messages.WARNING – для предупреждений.
- messages.ERROR – для ошибок.
modeladmin.message_user(request, 'Успех!', messages.SUCCESS)
Практическое задание
- Создайте действие, которое будет массово блокировать (делать
is_active=False) пользователей. - Добавьте подтверждение для этого действия, чтобы избежать случайного выполнения.
- Реализуйте кастомное действие, которое отправляет напоминания (email) пользователям.
- Ограничьте доступ к некоторым действиям для определённых групп пользователей (например, только для администраторов).
Постарайтесь, чтобы все эти действия работали в вашей админ-зоне, и убедитесь, что ваши пользователи довольны (или хотя бы не в ярости).
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ