You have seen actions in Django admin already. Those are options in the dropdown on the change list:

image

Let's make two actions for our Category model: one to enable and another to disable a category.

We have this Category model:

class Category(models.Model):
    name = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200, unique=True)
    is_active = models.BooleanField(default=True, db_index=True)

Open admin.py, we have a basic ModelAdmin for it there:

class CategoryAdmin(admin.ModelAdmin):
    list_display = (
        "name",
        "slug",
        "is_active",
        "id",
    )


admin.site.register(Category, CategoryAdmin)

There are two ways we can add actions: - define an action within the ModelAdmin class and it only be used here - define an action outside any ModelAdmin class and it will be possible to reuse it in other ModelAdmin classes.

Let's try both.

Defining a Django Admin Action within a ModelAdmin class

class CategoryAdmin(admin.ModelAdmin):
    list_display = (
        "name",
        "slug",
        "is_active",
        "id",
    )
    actions = [
        "make_inactive",
    ]

    @admin.action(description="Deactivate selected categories")
    def make_inactive(self, request, queryset):
        for category in queryset:
            category.is_active = False
            category.save()


admin.site.register(Category, CategoryAdmin)

What we did here is this: - add a method to CategoryAdmin called make_inactive decorated by @admin.action - add the actions attribute to the CategoryAdmin where we specify the action as a string. Specifying it as a string tells Django to this actions as a method.

image

Defining Django Admin Action outside a ModelAdmin

This approach allows you to define actions in a way that they can be reused by other ModelAdmin instances.

Marking active/inactive is a great example of a Django Admin Action for such reusability.

def make_active(modeladmin, request, queryset):
    for obj in queryset:
        obj.is_active = True
        obj.save()


make_active.short_description = "Activate selected %(verbose_name_plural)s"


class CategoryAdmin(admin.ModelAdmin):
    list_display = (
        "name",
        "slug",
        "is_active",
        "id",
    )
    actions = [
        "make_inactive",
        make_active,
    ]

    @admin.action(description="Deactivate selected categories")
    def make_inactive(self, request, queryset):
        for category in queryset:
            category.is_active = False
            category.save()


admin.site.register(Category, CategoryAdmin)

Now our Django admin actions for our Category page looks like this:

image

You can now add make_active to actions of other ModelAdmin classes.

Pay attention to this line:

make_active.short_description = "Activate selected %(verbose_name_plural)s"

From Django Docs:

Action descriptions are %-formatted and may contain '%(verbose_name)s' and '%(verbose_name_plural)s' placeholders, which are replaced, respectively, by the model’s verbose_name and verbose_name_plural.

Read more in Django Admin Actions Documentation