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. Обмежте доступ до деяких дій для певних груп користувачів (наприклад, тільки для адміністраторів).

Спробуйте, щоб усі ці дії працювали у вашій адмін-зоні, і переконайтеся, що ваші користувачі задоволені (або хоча б не у гніві).

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ