Python装饰器错误:decorated_view() 至少需要2个参数(给定1个)
我想在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"
}
因为POST
和PUT/DELETE/GET
都包含相同的参数,那么在PUT/DELETE/GET
请求的情况下,发生了什么不同的事情呢?
1 个回答
0
问题是,你包装的一些函数接受一个叫做 request
的参数,而其他一些函数则接受一个叫做 bundle
的参数,但你的装饰器总是把这个参数称为 request
。这样一来,当 Tastypie 的内部代码尝试传递一个 bundle
关键字参数时,就会出错。因为你的装饰器并不知道有一个叫 bundle
的参数,所以它会把这个参数放到 **kwargs
中,而你的装饰器就收不到 request
参数了。
我对 Django 或 Tastypie 的了解不够,不太清楚 request
和 bundle
之间的区别。如果它们其实是同一个东西,只是名字不同,那么你可以把这个参数放到 kwargs
中,然后让你的装饰器手动去查找这个参数,看看是 request
还是 bundle
。但如果 request
和 bundle
的意思不一样,那你可能需要写两个不同的装饰器来分别处理它们。