Python装饰器错误:decorated_view() 至少需要2个参数(给定1个)

0 投票
1 回答
913 浏览
提问于 2025-04-18 08:22

我想在Django中用我的装饰器来装饰视图。简单来说,我想在用户访问API的任何端点之前,先用一个auth-token密钥来验证用户的身份。

这是我的代码:

class XYZResource(ModelResource):

    class Meta:
        queryset = XYZ.objects.all()
        resource_name = 'xyz'
        allowed_methods = ['get','post','delete','put']

    @roles_accepted('admin','staff')
    def obj_get(self, bundle, **kwargs):
        ..............

    @roles_accepted('admin','staff')
    def get_object_list(self, request): 
        ......


    @roles_accepted('admin','staff')
    def obj_create(self, bundle, **kwargs):
         ......

    @roles_accepted('admin','staff')
    def obj_update(self, bundle, **kwargs):
             ......


    @roles_accepted('admin','staff')
    def obj_delete(self, bundle, **kwargs):
             ......

这是我的装饰器:

def roles_accepted(*roles):
    def wrapper(fn):
        def decorated_view(self,request,*args, **kwargs):
            if check_role(request) in roles  or check_role(request.request) in roles: # for POST,PUT,DELETE where bundle is passed, 
                return fn(self,request,*args, **kwargs)                               # auth_token is contained in bundle.request
            raise ImmediateHttpResponse(create_json_response({"error": "Unauthorized user"}, HttpUnauthorized)) 
        return decorated_view
    return wrapper

我遇到的错误是,当我请求POST/GET-ALL时,一切正常,但当我进行'GET/DELETE/PUT'请求时,就会出现问题,提示如下:

{
  "error_message": "decorated_view() takes at least 2 arguments (1 given)",
  "traceback": "Traceback (most recent call last):\n\n  File \"/usr/local/lib/python2.7/dist-packages/tastypie/resources.py\", line 195, in wrapper\n    response = callback(request, *args, **kwargs)\n\n  File \"/usr/local/lib/python2.7/dist-packages/tastypie/resources.py\", line 435, in dispatch_detail\n    return self.dispatch('detail', request, **kwargs)\n\n  File \"/usr/local/lib/python2.7/dist-packages/tastypie/resources.py\", line 458, in dispatch\n    response = method(request, **kwargs)\n\n  File \"/usr/local/lib/python2.7/dist-packages/tastypie/resources.py\", line 1408, in put_detail\n    updated_bundle = self.obj_update(bundle=bundle, **self.remove_api_resource_names(kwargs))\n\nTypeError: decorated_view() takes at least 2 arguments (1 given)\n"
}

因为POSTPUT/DELETE/GET都包含相同的参数,那么在PUT/DELETE/GET请求的情况下,发生了什么不同的事情呢?

1 个回答

0

问题是,你包装的一些函数接受一个叫做 request 的参数,而其他一些函数则接受一个叫做 bundle 的参数,但你的装饰器总是把这个参数称为 request。这样一来,当 Tastypie 的内部代码尝试传递一个 bundle 关键字参数时,就会出错。因为你的装饰器并不知道有一个叫 bundle 的参数,所以它会把这个参数放到 **kwargs 中,而你的装饰器就收不到 request 参数了。

我对 Django 或 Tastypie 的了解不够,不太清楚 requestbundle 之间的区别。如果它们其实是同一个东西,只是名字不同,那么你可以把这个参数放到 kwargs 中,然后让你的装饰器手动去查找这个参数,看看是 request 还是 bundle。但如果 requestbundle 的意思不一样,那你可能需要写两个不同的装饰器来分别处理它们。

撰写回答