Пользовательские кнопки в Django Admin

Введение

Стандартный интерфейс администратора Django имеет довольно широкий функционал. С его помощью вы можете в несколько строк настроить групповые действия, сортировку и поиск. Но порой ему не хватает совсем простых вещей. Например кнопок действий в таблице объектов.

Таблица в Django с кнопками действий

Сегодня мы рассмотрим как сделать простые «action buttons» для моделей джанго без скачивания каких либо библиотек. В конце текста будут ссылки на библиотеки, которые вам помогут, на случай если вариант делать вручную вам не подходит.

Описание проекта

Рассмотрим простой проект с некими заказами (заявками), у которых есть булево поле «Статус» с возможными значениями «Принято» и «Отклонено» соответственно.

from django.db import models
from django.contrib.auth.models import User
# Базовая модель заявок
class Order(models.Model):
    customer = models.ForeignKey(User, verbose_name="Заказчик", on_delete=models.CASCADE)
    message = models.CharField(max_length=30, verbose_name="Сообщение")
    status = models.BooleanField(default=False, verbose_name="Статус заявки")
 # Методы для смены статусов
    def Approve(self):
        self.status = True
        self.save()
    def Deny(self):
        self.status = False
        self.save()
    class Meta:
        db_table = 'orders'
        verbose_name = 'Заявка'
        verbose_name_plural = 'Заявки'

В admin.py переопределена стандартная регистрация модели, где мы указываем на отрисовку конкретно двух столбцов.

from django.contrib import admin
# Импортируем модель заказов
from .models import Order
 # Регистрируем ее в админке
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    # Список отображаемых столбцов
    list_display = ("customer", "status")

Есть необходимость в смене статуса оператором системы. Но заходить в каждый объект занимает много времени. Отсюда задача: сделать в таблице объектов колонку с кнопками смены статуса заказа.

Решение

Все действо разворачивается в файле admin.py. Для получения столбца с кнопками достаточно определить в классе OrderAdmin метод возвращающий html код этих кнопок и указать его в list_display. Обработку их нажатий и получение ссылок определим там же, использовав get_urls.

from django.contrib import admin
from django.urls import path, reverse
from django.shortcuts import redirect
from django.utils.html import format_html
# Импортируем модель заказов
from .models import Order
# Регистрируем ее в админке
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    # Список отображаемых столбцов, куда мы добавили метод возвращающий кнопки
    list_display = ("customer", "status", "ApproveButton")
    # Метод возвращающий кнопки html
    @staticmethod
    def ApproveButton(self):
        return format_html(f'<a class="button" href="{reverse("admin:order_apr",args=[self.pk])}">Потвердить</a><a class="button" href="{reverse("admin:order_deny", args=[self.pk])}">Отклонить</a>') #ApproveButton.short_description = "test"
     # Добавляем к существующим ссылкам в админке, ссылки на кнопки для их обработки
    def get_urls(self):
        urls = super().get_urls()
        shard_urls = [path('apr/<int:pid>', self.admin_site.admin_view(self.setApprove), name="order_apr"),         path('deny/<int:pid>', self.admin_site.admin_view(self.setDeny), name="order_deny"), ]
        # Список отображаемых столбцов 
        return shard_urls + urls
    # Обработка событий кнопок
    def setApprove(self, obj, pid=0):
        if (pid != 0):
            # Поиск обьекта
            order = Order.objects.get(pk=pid)
            if order:
                 # если найден вызываем необходимый нам метод
                order.Approve()
        # В конце в любом случае делаем редирект на страницу обьектов
        return redirect(reverse("admin:orders_order_changelist"))
    def setDeny(self, obj, pid=0):
         if (pid != 0): 
            order = Order.objects.get(pk=pid)
            if order:
                order.Deny()
        return redirect(reverse("admin:orders_order_changelist"))

Где return redirect(reverse("admin:orders_order_changelist")) не забудьте поменять orders_order на свой вариант вида app_name_model.

Ниже вы можете скачать полученный проект и попробовать сами.

Вариант с библиотекой

Как и обещал, вот библиотека на случай, если кнопки нужны часто и много.

from django_object_actions import DjangoObjectActions
class MyModelAdmin(DjangoObjectActions, admin.ModelAdmin):
     def toolfunc(self, request, obj):
         pass
     toolfunc.label = "This will be the label of the button"  # optional
     toolfunc.short_description = "This will be the tooltip of the button"  # optional
     def make_published(modeladmin, request, queryset):
         queryset.update(status='p')
     change_actions = ('toolfunc', )
     changelist_actions = ('make_published', )
5 1 vote
Рейтинг статьи
Подписаться
Уведомление о
guest
0 комментариев
Inline Feedbacks
View all comments