Django Admin Actions on single object

Viewed 8805

The admin actions seem to work on several items selected in the list view of django admin interface:

In my case I would like to have a simple action button on the change (one item) view.

Is there a way to make the django admin actions available there?

I know that I can walk around this problem by going to the list view, and select one item there. But it would be more nice to have it directly available.

4 Answers

Not the same as the topic starter asked, but this snippet allows to have Single Object action from on the list page with minimum amount of code

BaseAction code

class AdminActionError(Exception):
    pass


class AdminObjectAction:
    """Base class for Django Admin actions for single object"""

    short_description = None
    exp_obj_state = {}

    def __init__(self, modeladmin, request, queryset):
        self.admin = modeladmin
        self.request = request
        self.queryset = queryset
        self.__call__()

    def validate_qs(self):
        count = self.queryset.count()
        if count != 1:
            self.error("You must select one object for this action.")

        if self.exp_obj_state:
            if self.queryset.filter(**self.exp_obj_state).count() != 1:
                self.error(f'Selected object does not meet the requirements: {self.exp_obj_state}')

    def error(self, msg):
        raise AdminActionError(msg)

    def get_object(self):
        return self.queryset.get()

    def process_object_action(self, obj):
        pass

    def validate_obj(self, obj):
        pass

    def __call__(self, *args, **kwargs):
        try:
            self.validate_qs()
            obj = self.get_object()
            self.validate_obj(obj)
        except AdminActionError as e:
            self.admin.message_user(self.request, f"Failed: {e}", level=messages.ERROR)
        else:
            with transaction.atomic():
                result = self.process_object_action(obj)

            self.admin.message_user(self.request, f"Success: {self.short_description}, {result}")

Custom Action [minimum amount of code]

class RenewSubscriptionAction(AdminObjectAction):
    short_description = 'Renew subscription'

    exp_obj_state = {
        'child': None,
        'active_status': True,        
    }

    def process_object_action(self, obj):
        manager = RenewManager(user=obj.user, subscription=obj)
        return manager.process()

AdminClass

class SomeAdmin(admin.ModelAdmin):
    actions = [RenewSubscriptionAction]
Related