django-unfold icon indicating copy to clipboard operation
django-unfold copied to clipboard

Object-dependent actions

Open juanfcocontreras opened this issue 11 months ago • 3 comments

I would like my detail actions to be dependent (to be shown or hidden) depending on certain values contained in the fields. To do this I use the function get_actions_detail, but it doesn't get the object obj, so I can't access the fields.

I have seen both a pull request (closed without accepting) and an issue that the creator himself closes but not with a solution.

So my question is if right now there is any way to show or hide actions depending on object values?

If not, could the Pull Request be reconsidered? I think it is a minor change and provides functionality that may be useful to users (as evidenced by their votes).

Thanks in advance!

juanfcocontreras avatar Mar 07 '24 15:03 juanfcocontreras

You may get the object id from request.path.

try:
    obj_id = int(request.path.split("/")[-3])
except:
    pass

Apart from this, you can “hide” unwanted actions in a formview by overriding get_actions_detail and/or get_actions_submit_line methods.

I’ll give you an example tomorrow.

justinqian42 avatar Apr 05 '24 09:04 justinqian42

Here's an example for your reference.

@admin.register(YourModel)
class YourModelAdmin(ModelAdmin

    actions_detail = ["action_one"]

    @action(description=("One"), permissions=["add"], url_path="one", attrs={})
    def action_one(self, request: HttpRequest, object_id: int):
        # your business logics
        pass

    def get_actions_detail(self, request: HttpRequest):
        actions_detail = super().get_actions_detail(request)
        try:
            obj = YourModel.objects.get(id=int(request.path.split("/")[-3]))
        except:
            return actions_detail
        actions = []
        for action in actions_detail:
            if "_action_one" in action.action_name and <your conditions>:
                # do something here
                
            else:
                actions.append(action) # do nothing but only append the action
        return actions

justinqian42 avatar Apr 06 '24 00:04 justinqian42

Another way is to create your own has_xxxx_permission method.

@admin.register(YourModel)
class YourModelAdmin(ModelAdmin

    actions_detail = ["action_one"]

    @action(description=("One"), permissions=["approve"], url_path="one", attrs={})
    def action_one(self, request: HttpRequest, object_id: int):
        # your business logics
        pass

    def has_approve_permission(self, request, obj=None):
        # your business logics
        return True if <conditions are met> else False

justinqian42 avatar Apr 14 '24 08:04 justinqian42

Added object_id for detail and submit line actions #552

lukasvinclav avatar Jul 09 '24 14:07 lukasvinclav