JavaRush /Курсы /Модуль 3: Django /Работа с действиями (actions) в админке

Работа с действиями (actions) в админке

Модуль 3: Django
11 уровень , 6 лекция
Открыта

Сегодня мы займёмся настоящей магией – создадим свои действия (actions) для массового управления объектами в админке. Что такое действия (actions) в Django Admin? Давайте представим, что вы управляете огромным списком пользователей. Теперь предположим, что вам нужно удалить или изменить сразу N объектов (например, активировать пользователей или перевести их в группу "VIP"). Конечно, можно открыть каждый объект и редактировать его вручную, но зачем, если мы можем применить действие сразу ко всем выбранным объектам? Вот тут-то и вступает в игру функционал actions.

Действия (actions) в Django Admin – это кастомные функции, которые вы можете выполнить над одним или несколькими объектами. Они добавляются в выпадающий список над списком объектов.

Пример выпадающего списка с действиями вы наверняка видели:

  • "Удалить выбранные объекты" – это встроенное действие.
  • А мы научимся добавлять свои, кастомные действия.

Как работают действия в Django Admin?

Действия связаны с классом ModelAdmin. Они регистрируются в специальном атрибуте actions этого класса. Действия принимают три параметра:

  1. modeladmin – текущий экземпляр ModelAdmin.
  2. request – HTTP-запрос.
  3. 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]

🖥 Что здесь происходит?

  1. Мы создали функцию activate_users, которая принимает queryset и обновляет поле is_active для всех выбранных пользователей.
  2. Использовали декоратор @admin.action, чтобы задать описание действия, которое будет отображаться в выпадающем списке.
  3. Добавили это действие в список 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]

Как это работает?

  1. При первом вызове действия мы отправляем администратору предупреждение (через message_user).
  2. Если администратор повторяет действие (проверяем по наличию '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)

Практическое задание

  1. Создайте действие, которое будет массово блокировать (делать is_active=False) пользователей.
  2. Добавьте подтверждение для этого действия, чтобы избежать случайного выполнения.
  3. Реализуйте кастомное действие, которое отправляет напоминания (email) пользователям.
  4. Ограничьте доступ к некоторым действиям для определённых групп пользователей (например, только для администраторов).

Постарайтесь, чтобы все эти действия работали в вашей админ-зоне, и убедитесь, что ваши пользователи довольны (или хотя бы не в ярости).

1
Задача
Модуль 3: Django, 11 уровень, 6 лекция
Недоступна
Создание простого действия в админке
Создание простого действия в админке
1
Задача
Модуль 3: Django, 11 уровень, 6 лекция
Недоступна
Создание действия с подтверждением удаления
Создание действия с подтверждением удаления
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ