首页 > 解决方案 > Django DRF在自定义装饰器中获取请求查询参数,应用于viewsets.ViewSet中的函数

问题描述

在django rest框架中创建自定义viewsets.ViewSet时,我们可以在该ViewSet中的特定函数上应用自定义装饰器吗?

class UserViewSet(viewsets.ViewSet):
    """
    Example empty viewset demonstrating the standard
    actions that will be handled by a router class.

    If you're using format suffixes, make sure to also include
    the `format=None` keyword argument for each action.
    """

    @permission_classes([IsAuthenticated])
    @custom_decorator_1()
    def list(self, request):
        pass

    @custom_decorator_2()
    def create(self, request):
        pass

    @custom_decorator_3()
    def retrieve(self, request, pk=None):
        pass

    def update(self, request, pk=None):
        pass

    def partial_update(self, request, pk=None):
        pass

    def destroy(self, request, pk=None):
        pass

如果是,那么我们如何在 ViewSet 上应用的自定义装饰器中获取查询参数?或者是否有任何替代解决方案可以实现这一点,我可以在 ViewSet 操作上应用多个装饰器?

现在我正在尝试以这种方式做到这一点:

def custom_decorator():
    """
    Decorator for views that checks that the user passes the given test,
    redirecting to the log-in page if necessary. The test should be a callable
    that takes the user object and returns True if the user passes.
    """

    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):

            role = request.query_params['role']
            
            return view_func(request, *args, **kwargs)

        return wrapper

    return decorator

收到错误:

AttributeError:“UserViewSet”对象没有属性“query_params”

标签: pythondjangodjango-rest-framework

解决方案


Django 提供了一种在基于类的视图上使用装饰器的简单方法(这也适用于 DRF):

from django.utils.decorators import method_decorator

@method_decorator(login_required) #replace login_required with your own decorator
    def list(self, request):
        pass

更多信息:https ://docs.djangoproject.com/en/3.1/topics/class-based-views/intro/#decorating-the-class

但在你的情况下,我宁愿选择 DRF 自己的权限系统(https://www.django-rest-framework.org/api-guide/permissions/):

from rest_framework import permissions

class CustomerAccessPermission(permissions.BasePermission):
    def has_permission(self, request, view):
        return request.query_params['role'] == "admin" #or whatever as long as it is a boolean

推荐阅读