Skip to main content

Django Admin Actions

Django Admin's actions feature allows you to perform operations on multiple objects simultaneously. Actions are a powerful way to extend the Django Admin interface, enabling site administrators to perform bulk operations with just a few clicks.

Introduction

Actions in Django Admin appear as dropdown options above the list of objects in a change list page. The default action that comes with Django is "Delete selected objects," but you can create custom actions to perform any operation you need.

Django Admin Actions Screenshot

In this tutorial, you'll learn how to:

  • Use the default delete action
  • Create custom admin actions
  • Apply actions to selected objects
  • Register actions with your ModelAdmin
  • Create site-wide actions

Understanding Default Actions

By default, Django provides a "delete selected objects" action that allows administrators to delete multiple objects at once.

Here's how it works:

  1. Select one or more objects using the checkboxes
  2. Choose "Delete selected objects" from the dropdown menu
  3. Click "Go"
  4. Confirm the deletion on the next page

This simple workflow saves administrators from having to delete objects one by one.

Creating Custom Admin Actions

Let's create a custom action that allows you to mark multiple blog posts as "published" at once.

Step 1: Define Your Action Function

An action is a function that takes three parameters:

  • modeladmin: The current ModelAdmin instance
  • request: The current HttpRequest object
  • queryset: A QuerySet containing the selected objects
python
def make_published(modeladmin, request, queryset):
queryset.update(status='published')
make_published.short_description = "Mark selected posts as published"

The .short_description attribute sets what appears in the dropdown menu.

Step 2: Register the Action with ModelAdmin

Once you've defined your action function, you need to register it with your ModelAdmin:

python
from django.contrib import admin
from .models import BlogPost

class BlogPostAdmin(admin.ModelAdmin):
list_display = ('title', 'status', 'created_at')
actions = [make_published]

admin.site.register(BlogPost, BlogPostAdmin)

Now, the "Mark selected posts as published" action will appear in the dropdown menu alongside the default delete action.

Adding Message Confirmation

It's good practice to provide feedback to users when an action is performed. Let's enhance our action to display a message:

python
from django.contrib import messages

def make_published(modeladmin, request, queryset):
updated = queryset.update(status='published')
if updated == 1:
message = "1 post was"
else:
message = f"{updated} posts were"
messages.success(request, f"{message} successfully marked as published.")
make_published.short_description = "Mark selected posts as published"

Actions with Intermediate Pages

For more complex actions that require additional input or confirmation, you can return an HttpResponse instead of updating objects directly:

python
from django.shortcuts import render
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME

def archive_posts(modeladmin, request, queryset):
if request.POST.get('post'):
# User confirmed the action
archive_reason = request.POST.get('archive_reason')
for post in queryset:
post.status = 'archived'
post.archive_note = archive_reason
post.save()

modeladmin.message_user(
request,
f"{queryset.count()} posts were archived with reason: {archive_reason}"
)
return None

# First time the action is run, show a confirmation page
return render(
request,
'admin/archive_posts.html',
context={
'posts': queryset,
'media': modeladmin.media,
'action_checkbox_name': ACTION_CHECKBOX_NAME,
}
)
archive_posts.short_description = "Archive selected posts"

For this to work, you'll need to create a template file at templates/admin/archive_posts.html:

html
{% extends "admin/base_site.html" %}

{% block content %}
<h1>Archive Posts</h1>
<p>You are about to archive the following posts:</p>
<ul>
{% for post in posts %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
<form action="" method="post">
{% csrf_token %}
<div>
<label for="archive_reason">Archive Reason:</label>
<input type="text" name="archive_reason" required>
</div>

{% for post in posts %}
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ post.pk }}">
{% endfor %}
<input type="hidden" name="action" value="archive_posts">
<input type="hidden" name="post" value="yes">
<input type="submit" value="Confirm Archive">
</form>
<a href="{% url 'admin:blogapp_blogpost_changelist' %}">Cancel</a>
{% endblock %}

Site-Wide Actions

If you want an action to be available across multiple models, you can create a site-wide action:

python
# In your main admin.py file
from django.contrib import admin

def mark_as_featured(modeladmin, request, queryset):
if hasattr(queryset.model, 'featured'):
queryset.update(featured=True)
modeladmin.message_user(request, "Selected items marked as featured.")
mark_as_featured.short_description = "Mark selected items as featured"

# Add it to the admin site's actions
admin.site.add_action(mark_as_featured)

Disabling Actions

You can disable the default delete action or any other action for a specific ModelAdmin:

python
from django.contrib import admin
from .models import ImportantDocument

class ImportantDocumentAdmin(admin.ModelAdmin):
actions = None # Disables all actions
# OR
def get_actions(self, request):
actions = super().get_actions(request)
if 'delete_selected' in actions:
del actions['delete_selected'] # Only disable delete action
return actions

admin.site.register(ImportantDocument, ImportantDocumentAdmin)

Real-World Example: Export as CSV

Here's a practical example that shows how to create an action to export selected objects as a CSV file:

python
import csv
from django.http import HttpResponse
from django.contrib import admin
from .models import Customer

def export_as_csv(modeladmin, request, queryset):
meta = modeladmin.model._meta
field_names = [field.name for field in meta.fields]

response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = f'attachment; filename={meta.verbose_name_plural}.csv'

writer = csv.writer(response)
writer.writerow(field_names)

for obj in queryset:
writer.writerow([getattr(obj, field) for field in field_names])

return response

export_as_csv.short_description = "Export selected objects as CSV"

class CustomerAdmin(admin.ModelAdmin):
list_display = ('name', 'email', 'phone', 'created_at')
actions = [export_as_csv]

admin.site.register(Customer, CustomerAdmin)

With this action, administrators can select customers and download their information as a CSV file.

Handling Permissions and Security

You can control who has access to specific actions using Django's permission system:

python
def make_featured(modeladmin, request, queryset):
# Check if user has permission
if not request.user.has_perm('blog.can_feature_posts'):
messages.error(request, "You do not have permission to feature posts.")
return

# Perform the action
queryset.update(featured=True)
messages.success(request, f"{queryset.count()} posts marked as featured.")
make_featured.short_description = "Mark selected posts as featured"

Summary

Django Admin actions provide a powerful way to perform bulk operations in your admin interface. Key points to remember:

  • Actions are functions that take modeladmin, request, and queryset parameters
  • You can add actions to specific ModelAdmin classes or make them site-wide
  • Actions can perform operations directly or show intermediate pages for additional input
  • You can provide user feedback using Django's messaging framework
  • Actions can be permission-controlled for security

By using admin actions effectively, you can significantly improve the usability of your Django admin interface and save time for your administrators.

Exercises

  1. Create an action that toggles the "active" status of selected users
  2. Build an action that assigns selected objects to a specific category
  3. Create an advanced action that generates a PDF report of selected items
  4. Implement an action with an intermediate page that allows bulk-updating of multiple fields

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)