在最近的 SharePlat 的项目中,我想使用一些 decorator 来进行处理,有些 decorator 需要一些参数,因此上生成的 decorator 就有一些复杂,比如:
def template(templatename): """ render the func's result into a template """ def _render(func): def _f(*args, **kwargs): result = func(*args, **kwargs) return render_to_response(templatename, context_instance=RequestContext(args[0], result)) return _f return _render
从上面可以看到template带参数,按decorator的生成要求,它要再返回一个decorator函数才行,因此上又定义了两个函数:_render和_f。而返回_render则是一个decorator函数。
那么不带参数的话,可以简化一些:
def check_userid(f): """ render the func's result into a template """ @decorator.errorhandle def _f(*args, **kwargs): request = args[0] object_id = kwargs['object_id'] try: person = User.objects.get(pk=int(object_id)) except User.DoesNotExist: raise Exception, "用户 ID (%s) 不存在!" % object_id return f(*args, **kwargs) return _f
这个check_userid没有多作的参数,因此,在它内部只定义了一个函数。但是因为这个函数的功能是为了检查参数中给定的object_id是否存在,所以需要从传入的函数f中得到相应的参数进行处理。那么f的标准形式为:
@check_useriddef user_detail(request, object_id):
那么在check_userid需要得到request和object_id两个值。因此上在_f函数中可能通过args[0]来得到request。但是你不能使用args[1]来得到object_id。为什么,因为django在调用user_detail时,会使用关键字的方式来传入object_id,也就是在_f中你会在kwargs中看到'object_id'这个值。因此,object_id需要通过kwargs['object_id']来得到。这一点需要注意。虽然定义user_detail方法没有关键字参数,但是django在调用时会使用关键字参数,所以造成后面的参数取得会有问题。
update: 2006/12/23
后来想到为什么 django 会将object_id 以关键字参数的方式传入呢?原因还在于urls.py中的定义,如果你使用了 (?P<name>)的形式,那么 django 会自动使用关键字参数来调用views方法,如果只是简单的正则式则不会。所以建议在定义url时,模式最好一致,以减少不必要的麻烦。 |