Django Admin list actions are meant to be used to perform operations in bulk. All Django Admin list views already come
with a default action “Delete selected <ModelName>s”. In this short tutorial I will guide you through the steps
to create your own list actions.
Creating the Action Function
Each action in the list is a regular Python function that takes three parameters: the current ModelAdmin ,
a HttpRequest object (just like a view function) and a QuerySet , which is the list of selected model instances.
Those Action Functions can live inside the admin.py module of your app. But if they start to get really big,
you can define them outside the admin.py .
Following is the skeleton for a Action Function :
def my_admin_action ( modeladmin , request , queryset ):
# do something with the queryset
my_admin_action . short_description = 'My admin action'
Simple Example
Consider the following model and model admin:
models.py
from django.db import models
class Book ( models . Model ):
HARDCOVER = 1
PAPERBACK = 2
EBOOK = 3
BOOK_TYPES = (
( HARDCOVER , 'Hardcover' ),
( PAPERBACK , 'Paperback' ),
( EBOOK , 'E-book' ),
)
title = models . CharField ( max_length = 50 )
publication_date = models . DateField ( null = True )
author = models . CharField ( max_length = 30 , blank = True )
price = models . DecimalField ( max_digits = 5 , decimal_places = 2 )
pages = models . IntegerField ( blank = True , null = True )
book_type = models . PositiveSmallIntegerField ( choices = BOOK_TYPES )
class Meta :
verbose_name = 'book'
verbose_name_plural = 'books'
admin.py
from django.contrib import admin
from .models import Book
class BookAdmin ( admin . ModelAdmin ):
list_display = [ 'title' , 'publication_date' , 'author' , 'price' , 'book_type' ]
admin . site . register ( Book , BookAdmin )
Let’s say we want to create a list action to apply a 10% discount to the selected books. It would be as simple as:
admin.py
import decimal
from django.contrib import admin
from .models import Book
def apply_discount ( modeladmin , request , queryset ):
for book in queryset :
book . price = book . price * decimal . Decimal ( '0.9' )
book . save ()
apply_discount . short_description = 'Apply 10 %% discount'
class BookAdmin ( admin . ModelAdmin ):
list_display = [ 'title' , 'publication_date' , 'author' , 'price' , 'book_type' ]
actions = [ apply_discount , ] # <-- Add the list action function here
admin . site . register ( Book , BookAdmin )
Don’t forget to add the name of the function to the actions
list, and the result will be something like this:
Tip!
You can optimize the apply_discount
function using a F()
expression:
from django.db.models import F
def apply_discount ( modeladmin , request , queryset ):
queryset . update ( price = F ( 'price' ) * decimal . Decimal ( '0.9' ))
If you want to learn more about F()
expressions, I have a post dedicated to that subject:
Django Tips #13 Using F() Expressions
Export to CSV Example
You can also use the list action to return a HttpResponse
. A simple export to CSV example:
admin.py
import decimal , csv
from django.contrib import admin
from django.http import HttpResponse
from django.db.models import F
from .models import Book
def apply_discount ( modeladmin , request , queryset ):
queryset . update ( price = F ( 'price' ) * decimal . Decimal ( '0.9' ))
apply_discount . short_description = 'Apply 10 %% discount'
def export_books ( modeladmin , request , queryset ):
response = HttpResponse ( content_type = 'text/csv' )
response [ 'Content-Disposition' ] = 'attachment; filename="books.csv"'
writer = csv . writer ( response )
writer . writerow ([ 'Title' , 'Publication Date' , 'Author' , 'Price' , 'Pages' , 'Book Type' ])
books = queryset . values_list ( 'title' , 'publication_date' , 'author' , 'price' , 'pages' , 'book_type' )
for book in books :
writer . writerow ( book )
return response
export_books . short_description = 'Export to csv'
class BookAdmin ( admin . ModelAdmin ):
list_display = [ 'title' , 'publication_date' , 'author' , 'price' , 'book_type' ]
actions = [ apply_discount , export_books , ]
admin . site . register ( Book , BookAdmin )
You can read more about data export here in the blog:
List Action as Model Admin Method
An alternative way to implement it is by creating the list action function as a method of the admin class:
class BookAdmin ( admin . ModelAdmin ):
list_display = [ 'title' , 'publication_date' , 'author' , 'price' , 'book_type' ]
actions = [ 'apply_discount' , export_books ]
def apply_discount ( self , request , queryset ):
queryset . update ( price = F ( 'price' ) * decimal . Decimal ( '0.9' ))
apply_discount . short_description = 'Apply 10 %% discount'
Pass the method name as a string to the actions
list, and rename the modeladmin
keyword argument to self
.
Conclusions
There is much more you can do with the admin list actions. Read more in the
official documentation .
The example used in this tutorial is available on GitHub:
sibtc/django-admin-list-actions