Stage 4 — Custom list actions

Goal

Add a bulk action on the list view: select rows, pick a new category, apply to all. Built-in bulk delete (from stage 0) works the same way — subclass ListActionView, tag it list_action, and append it to the controller routes.

Model

from django.db import models


class Post(models.Model):
    title = models.CharField(max_length=200)
    category = models.CharField(max_length=50, blank=True)

    def __str__(self):
        return self.title

Controller and registration

from django import forms
from django.utils.translation import gettext_lazy as _, ngettext

import djmvc

from .models import Post


class SetCategoryForm(forms.Form):
    category = forms.CharField(max_length=50, label=_("Category"))


class SetCategoryView(djmvc.generic.ListActionView):
    """Bulk-update category on selected rows."""

    title = _("Set category")
    icon = "tag"
    color = "info"
    message = _("Choose a category for the selected posts.")
    form_class = SetCategoryForm

    def form_valid(self, form):
        self.object_list.update(category=form.cleaned_data["category"])
        return super().form_valid(form)

    def get_form_valid_message(self):
        count = self.object_list.count()
        return ngettext(
            "Updated category on %(count)d post.",
            "Updated category on %(count)d posts.",
            count,
        ) % {"count": count}


class PostController(djmvc.ModelController):
    model = Post
    icon = 'chat-square-text'

    routes = djmvc.ModelController.routes + [
        SetCategoryView,
    ]


djmvc.site.routes.append(PostController)

SetCategoryView receives selected primary keys as pks (query string from the list action bar). object_list is the scoped queryset intersection. form_valid runs your bulk logic — here a single QuerySet.update.

User-visible strings use gettext and ngettext so success messages pluralize correctly.

The list template discovers permitted actions as view.list_actions and renders them in <list-action-bar> next to the default delete action.

Try it

Visit http://localhost:8000/post/, create a few posts, select rows, and click Set category:

List action bar with row selection

Selected rows open the floating <list-action-bar> with permitted bulk actions.

Set category bulk action modal

Custom SetCategoryView — same pattern as the built-in bulk delete shown in Stage 0 — Register a model.

Tests

tests/test_stage4.py on GitHub

Next: Stage 5 — View mixins surveys the view mixins you can combine when building custom views.