The workhorse function for the admin action functions that follow.

def update_status(modeladmin, request, queryset, status):
    """The workhorse function for the admin action functions that follow."""
    # We loop over the objects here rather than use queryset.update() for
    # two reasons:
    #
    #  1. No one should ever be updating zillions of Topics or Questions, so
    #     performance is not an issue.
    #  2. To be tidy, we want to log what the user has done.
    #
    for obj in queryset:
        obj.status = status
        obj.save()
        # Now log what happened.
        # Use ugettext_noop() 'cause this is going straight into the db.
        log_message = ugettext_noop(u'Changed status to \'%s\'.' %
            obj.get_status_display())
        modeladmin.log_change(request, obj, log_message)

    # Send a message to the user telling them what has happened.
    message_dict = {
        'count': queryset.count(),
        'object': modeladmin.model._meta.verbose_name,
        'verb': dict(STATUS_CHOICES)[status],
    }
    if not message_dict['count'] == 1:
        message_dict['object'] = modeladmin.model._meta.verbose_name_plural
    user_message = ungettext(
        u'%(count)s %(object)s was successfully %(verb)s.',
        u'%(count)s  %(object)s were successfully %(verb)s.',
        message_dict['count']) % message_dict
    modeladmin.message_user(request, user_message)

    # Return None to display the change list page again and allow the user
    # to reload the page without getting that nasty "Send the form again ..."
    # warning from their browser.
    return None