django rest-framework里的异常处理
在rest-framework里的认证过程中:
class APIView(View):
def perform_authentication(self, request):
request.user
class Request(object):
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
在request类的user方法里,先判断了是否有_user属性,然后开启了一个上下文with wrap_attributeerrors()。
@contextmanager
def wrap_attributeerrors():
try:
yield
except AttributeError:
info = sys.exc_info()
exc = WrappedAttributeError(str(info[1]))
six.reraise(type(exc), exc, info[2])
这里的原函数是一个生成器,而with wrap_attributeerrors是一个用contextlib中的contextmanager装饰器装饰的一个上下文管理器,返回的是一个_GeneratorContextManager对象,而这个对象中重写了__enter__和__exit__方法,因此当with wrap_attributeerrors()时,调用的是_GeneratorContextManager中的__enter__,而这个方法里调用了原函数的next()方法,因此相当于启动了该生成器。然后回来执行上下文中的代码,如果出现异常,则会执行_GeneratorContextManager中的__exit__,也就是再执行一次make_context.next()函数,所以先会用自己所定义的异常处理方式来处理异常,然后再处理其他异常。