How to make custom decorator with multiple arguments?

Viewed 60

Here I am making a custom decorator with some kwargs parameter but the decorator is not working.

Error:

TypeError: my_decorator() takes 1 positional argument but 2 were given

Code

def my_decorator(title, **data):

    def _method_wrapper(view_method):

        def _arguments_wrapper(request, *args, **kwargs) :
            obj = Model.objects.get(title=title)
            if obj.relatedmodel_set.filter(**data).exists():
                return view_method(request, *args, **kwargs)
            raise PermissionDenied

        return _arguments_wrapper

    return _method_wrapper

#view

@my_decorator('title', {'is_manager':True})
def my_view(request, id):
1 Answers

You worked with **data, so this means you can pass named parameters, and then data is a dictionary that maps strings on the corresponding items.

Therefore you thus can call @my_decorator with:

@my_decorator('title', is_manager=True)
…

If you want to be able to pass positional parameters, for example Q objects, you can extend the signature with:

def my_decorator(title, *data, **datb):
    def _method_wrapper(view_method):

        def _arguments_wrapper(request, *args, **kwargs) :
            obj = Model.objects.get(title=title)
            if obj.relatedmodel_set.filter(*data, **datb).exists():
                return view_method(request, *args, **kwargs)
            raise PermissionDenied

        return _arguments_wrapper

    return _method_wrapper

In that case you can for example call the decorator with:

from django.db.models import Q

@my_decorator('title', Q(is_manager=True))
…
Related