2005-10-09 05:44:37 +08:00
|
|
|
"Functions that help with dynamically creating decorators for views."
|
|
|
|
|
2011-03-28 10:11:19 +08:00
|
|
|
from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS
|
2009-09-22 06:31:51 +08:00
|
|
|
|
2013-03-12 18:28:01 +08:00
|
|
|
from django.utils import six
|
|
|
|
|
|
|
|
|
2010-11-20 13:10:13 +08:00
|
|
|
class classonlymethod(classmethod):
|
|
|
|
def __get__(self, instance, owner):
|
|
|
|
if instance is not None:
|
|
|
|
raise AttributeError("This method is available only on the view class.")
|
|
|
|
return super(classonlymethod, self).__get__(instance, owner)
|
2009-10-16 04:25:20 +08:00
|
|
|
|
2013-03-12 18:28:01 +08:00
|
|
|
|
2010-02-09 23:02:39 +08:00
|
|
|
def method_decorator(decorator):
|
2009-09-22 06:31:51 +08:00
|
|
|
"""
|
2010-02-09 23:02:39 +08:00
|
|
|
Converts a function decorator into a method decorator
|
2009-09-22 06:31:51 +08:00
|
|
|
"""
|
2010-10-21 22:56:49 +08:00
|
|
|
# 'func' is a function at the time it is passed to _dec, but will eventually
|
|
|
|
# be a method of the class it is defined it.
|
2010-02-09 23:02:39 +08:00
|
|
|
def _dec(func):
|
|
|
|
def _wrapper(self, *args, **kwargs):
|
2010-10-21 22:56:49 +08:00
|
|
|
@decorator
|
2010-02-09 23:02:39 +08:00
|
|
|
def bound_func(*args2, **kwargs2):
|
|
|
|
return func(self, *args2, **kwargs2)
|
|
|
|
# bound_func has the signature that 'decorator' expects i.e. no
|
|
|
|
# 'self' argument, but it is a closure over self so it can call
|
|
|
|
# 'func' correctly.
|
2010-10-21 22:56:49 +08:00
|
|
|
return bound_func(*args, **kwargs)
|
|
|
|
# In case 'decorator' adds attributes to the function it decorates, we
|
|
|
|
# want to copy those. We don't have access to bound_func in this scope,
|
|
|
|
# but we can cheat by using it on a dummy function.
|
|
|
|
@decorator
|
|
|
|
def dummy(*args, **kwargs):
|
|
|
|
pass
|
|
|
|
update_wrapper(_wrapper, dummy)
|
|
|
|
# Need to preserve any existing attributes of 'func', including the name.
|
|
|
|
update_wrapper(_wrapper, func)
|
|
|
|
|
|
|
|
return _wrapper
|
2010-02-09 23:02:39 +08:00
|
|
|
update_wrapper(_dec, decorator)
|
|
|
|
# Change the name to aid debugging.
|
2010-05-13 19:11:27 +08:00
|
|
|
_dec.__name__ = 'method_decorator(%s)' % decorator.__name__
|
2010-02-09 23:02:39 +08:00
|
|
|
return _dec
|
2009-09-22 06:31:51 +08:00
|
|
|
|
|
|
|
|
|
|
|
def decorator_from_middleware_with_args(middleware_class):
|
|
|
|
"""
|
|
|
|
Like decorator_from_middleware, but returns a function
|
|
|
|
that accepts the arguments to be passed to the middleware_class.
|
|
|
|
Use like::
|
|
|
|
|
2009-09-23 05:21:51 +08:00
|
|
|
cache_page = decorator_from_middleware_with_args(CacheMiddleware)
|
2009-09-22 06:31:51 +08:00
|
|
|
# ...
|
|
|
|
|
|
|
|
@cache_page(3600)
|
|
|
|
def my_view(request):
|
|
|
|
# ...
|
|
|
|
"""
|
|
|
|
return make_middleware_decorator(middleware_class)
|
2007-07-05 19:10:27 +08:00
|
|
|
|
2010-02-09 23:02:39 +08:00
|
|
|
|
2005-10-09 05:44:37 +08:00
|
|
|
def decorator_from_middleware(middleware_class):
|
|
|
|
"""
|
|
|
|
Given a middleware class (not an instance), returns a view decorator. This
|
2009-09-22 06:31:51 +08:00
|
|
|
lets you use middleware functionality on a per-view basis. The middleware
|
|
|
|
is created with no params passed.
|
2005-10-09 05:44:37 +08:00
|
|
|
"""
|
2009-09-22 06:31:51 +08:00
|
|
|
return make_middleware_decorator(middleware_class)()
|
|
|
|
|
2010-05-13 19:11:27 +08:00
|
|
|
|
2010-03-12 21:06:13 +08:00
|
|
|
def available_attrs(fn):
|
|
|
|
"""
|
|
|
|
Return the list of functools-wrappable attributes on a callable.
|
2013-03-12 18:28:01 +08:00
|
|
|
This is required as a workaround for http://bugs.python.org/issue3445
|
|
|
|
under Python 2.
|
2010-03-12 21:06:13 +08:00
|
|
|
"""
|
2013-03-12 18:28:01 +08:00
|
|
|
if six.PY3:
|
|
|
|
return WRAPPER_ASSIGNMENTS
|
|
|
|
else:
|
|
|
|
return tuple(a for a in WRAPPER_ASSIGNMENTS if hasattr(fn, a))
|
2010-02-09 23:02:39 +08:00
|
|
|
|
2010-05-13 19:11:27 +08:00
|
|
|
|
2009-09-22 06:31:51 +08:00
|
|
|
def make_middleware_decorator(middleware_class):
|
|
|
|
def _make_decorator(*m_args, **m_kwargs):
|
|
|
|
middleware = middleware_class(*m_args, **m_kwargs)
|
|
|
|
def _decorator(view_func):
|
2011-05-02 00:46:02 +08:00
|
|
|
@wraps(view_func, assigned=available_attrs(view_func))
|
2009-09-22 06:31:51 +08:00
|
|
|
def _wrapped_view(request, *args, **kwargs):
|
|
|
|
if hasattr(middleware, 'process_request'):
|
|
|
|
result = middleware.process_request(request)
|
|
|
|
if result is not None:
|
|
|
|
return result
|
|
|
|
if hasattr(middleware, 'process_view'):
|
|
|
|
result = middleware.process_view(request, view_func, args, kwargs)
|
|
|
|
if result is not None:
|
|
|
|
return result
|
|
|
|
try:
|
|
|
|
response = view_func(request, *args, **kwargs)
|
2012-04-29 00:09:37 +08:00
|
|
|
except Exception as e:
|
2009-09-22 06:31:51 +08:00
|
|
|
if hasattr(middleware, 'process_exception'):
|
|
|
|
result = middleware.process_exception(request, e)
|
|
|
|
if result is not None:
|
|
|
|
return result
|
|
|
|
raise
|
2011-05-25 05:28:43 +08:00
|
|
|
if hasattr(response, 'render') and callable(response.render):
|
|
|
|
if hasattr(middleware, 'process_template_response'):
|
|
|
|
response = middleware.process_template_response(request, response)
|
|
|
|
# Defer running of process_response until after the template
|
|
|
|
# has been rendered:
|
|
|
|
if hasattr(middleware, 'process_response'):
|
|
|
|
callback = lambda response: middleware.process_response(request, response)
|
|
|
|
response.add_post_render_callback(callback)
|
|
|
|
else:
|
|
|
|
if hasattr(middleware, 'process_response'):
|
|
|
|
return middleware.process_response(request, response)
|
2009-09-22 06:31:51 +08:00
|
|
|
return response
|
2011-05-02 00:46:02 +08:00
|
|
|
return _wrapped_view
|
2010-02-09 23:02:39 +08:00
|
|
|
return _decorator
|
2009-09-22 06:31:51 +08:00
|
|
|
return _make_decorator
|