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)