Search code examples
pythonpython-3.xdjangodjango-rest-frameworkpartial-application

Using partial() on DRF's @action gives TypeError: "multiple values for argument"


I need similar @action detail routes on multiple ViewSets. I want to make sure they remain consistent. I don't want to put @action(methods=["post"], detail=True, url_path="something") in 20 places when I already know these parameters and the method handling the request will be the same everywhere.

My first attempt to solve htis was to put the method and its decorator in a base class and have my ViewSets inherit from it, but because decoration of methods is not inherited, DRF does not recognise my @actions as such in the inheriting classes. The methods get inherited but not the decorator.

So, to solve that, I could put @action everywhere but that would mean a duplication of its arguments in many places. I don't want that.

To avoid duplication, I am trying to specialise @action by using partial application. This will give me a custom @action decorator with the arguments which will be the same everywhere fixed in place.

This leaves me with something like this (example code):

specialised_action = partial(action, methods=["post"], detail=True, url_path="my-action-url")

class SomeViewSet(GenericViewSet):
    @specialised_action
    def action_handler(self, request, *args, **kwargs):
        print("do something")

But it doesn't work, I get this error:

TypeError: action() got multiple values for argument 'methods'

My questions:

  1. Why is methods passed multiple times?
  2. How can I fix this?
  3. Is there a better way to achieve consistent, duplication-free, @actions across many ViewSets?

Solution

  • The problem was that @action isn't a decorator, it returns a decorator. So there is no need to use partial().

    Instead of:

    specialised_action = partial(action, methods=["post"], detail=True, url_path="my-action-url")
    
    

    Simply do:

    specialised_action = action(methods=["post"], detail=True, url_path="my-action-url")
    

    And I got my specialised version of @action with fixed arguments.