Admin actions are useful for actions on set of objects. Django ships with a 'delete selected objects' action available to all models.
For example, you have Genres and Movies. You want to change genres for selected movies at once.
Action with intermediate page
Exmaple of models.py
class Genre(models.Model):
title = models.CharField(u'Title', max_length=100)
def __unicode__(self):
return self.title
class Movie(models.Model):
title = models.CharField(u'Title', max_length=200)
genre = models.ForeignKey(Genre, verbose_name=u'Genre')
score = models.IntegerField(u'Score')
def __unicode__(self):
return self.title
Example of form.py
from movies.models import *
class GenreForm(forms.Form):
genre = forms.ModelChoiceField(queryset=Genre.objects.all())
Example of admin.py
from django.contrib import messages
from django.shortcuts import render
from movies.forms import *
class MovieAdmin(admin.ModelAdmin):
list_display = ('title', 'genre',)
actions = ['set_genre_action']
def set_genre_action(self, request, queryset):
if 'do_action' in request.POST:
form = GenreForm(request.POST)
if form.is_valid():
genre = form.cleaned_data['genre']
updated = queryset.update(genre=genre)
messages.success(request, '{0} movies were updated'.format(updated))
return
else:
form = GenreForm()
return render(request, 'admin/movies/action_genre.html',
{'title': u'Choose genre',
'objects': queryset,
'form': form})
set_genre_action.short_description = u'Update genre of selected movies'
admin.site.register(Movie, MovieAdmin)
Example of template
{% extends "admin/base_site.html" %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
<input type="hidden" name="action" value="set_genre_action">
<input type="hidden" name="do_action" value="yes">
<div>
{{ form.genre }}
<input type="submit" class="default" style="float: none" value="Change">
{{ form.genre.errors }}
</div>
<h2>Change genre for next movies</h2>
<ul>
{% for object in objects %}
<li>
<a href="{{ object.pk }}/">{{ object.title }}</a> - {{ object.genre }}
<input type="hidden" name="_selected_action" value="{{ object.pk }}">
</li>
{% endfor %}
</ul>
</form>
{% endblock %}
_selected_action contains id of objects for queryset.
Action with input field in change list
Model for this example is the same.
Example of form.py
from django.contrib.admin.helpers import ActionForm
class UpdateScoreForm(ActionForm):
score = forms.IntegerField()
Example of admin.py
from django.contrib import messages
from movies.forms import *
class MovieAdmin(admin.ModelAdmin):
action_form = UpdateScoreForm
list_display = ('title', 'genre',)
actions = ['set_score_action']
def set_score_action(self, request, queryset):
score = int(request.POST['score'])
queryset.update(score=score)
messages.success(request, '{0} movies were updated'.format(queryset.count()))
set_score_action.short_description = u'Update score of selected movies'
admin.site.register(Movie, MovieAdmin)