web/lib/django/utils/decorators.py
changeset 38 77b6da96e6f1
equal deleted inserted replaced
37:8d941af65caf 38:77b6da96e6f1
       
     1 "Functions that help with dynamically creating decorators for views."
       
     2 
       
     3 import types
       
     4 try:
       
     5     from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS
       
     6 except ImportError:
       
     7     from django.utils.functional import wraps, update_wrapper, WRAPPER_ASSIGNMENTS  # Python 2.4 fallback.
       
     8 
       
     9 
       
    10 def method_decorator(decorator):
       
    11     """
       
    12     Converts a function decorator into a method decorator
       
    13     """
       
    14     def _dec(func):
       
    15         def _wrapper(self, *args, **kwargs):
       
    16             def bound_func(*args2, **kwargs2):
       
    17                 return func(self, *args2, **kwargs2)
       
    18             # bound_func has the signature that 'decorator' expects i.e.  no
       
    19             # 'self' argument, but it is a closure over self so it can call
       
    20             # 'func' correctly.
       
    21             return decorator(bound_func)(*args, **kwargs)
       
    22         return wraps(func)(_wrapper)
       
    23     update_wrapper(_dec, decorator)
       
    24     # Change the name to aid debugging.
       
    25     _dec.__name__ = 'method_decorator(%s)' % decorator.__name__
       
    26     return _dec
       
    27 
       
    28 
       
    29 def decorator_from_middleware_with_args(middleware_class):
       
    30     """
       
    31     Like decorator_from_middleware, but returns a function
       
    32     that accepts the arguments to be passed to the middleware_class.
       
    33     Use like::
       
    34 
       
    35          cache_page = decorator_from_middleware_with_args(CacheMiddleware)
       
    36          # ...
       
    37 
       
    38          @cache_page(3600)
       
    39          def my_view(request):
       
    40              # ...
       
    41     """
       
    42     return make_middleware_decorator(middleware_class)
       
    43 
       
    44 
       
    45 def decorator_from_middleware(middleware_class):
       
    46     """
       
    47     Given a middleware class (not an instance), returns a view decorator. This
       
    48     lets you use middleware functionality on a per-view basis. The middleware
       
    49     is created with no params passed.
       
    50     """
       
    51     return make_middleware_decorator(middleware_class)()
       
    52 
       
    53 
       
    54 def available_attrs(fn):
       
    55     """
       
    56     Return the list of functools-wrappable attributes on a callable.
       
    57     This is required as a workaround for http://bugs.python.org/issue3445.
       
    58     """
       
    59     return tuple(a for a in WRAPPER_ASSIGNMENTS if hasattr(fn, a))
       
    60 
       
    61 
       
    62 def make_middleware_decorator(middleware_class):
       
    63     def _make_decorator(*m_args, **m_kwargs):
       
    64         middleware = middleware_class(*m_args, **m_kwargs)
       
    65         def _decorator(view_func):
       
    66             def _wrapped_view(request, *args, **kwargs):
       
    67                 if hasattr(middleware, 'process_request'):
       
    68                     result = middleware.process_request(request)
       
    69                     if result is not None:
       
    70                         return result
       
    71                 if hasattr(middleware, 'process_view'):
       
    72                     result = middleware.process_view(request, view_func, args, kwargs)
       
    73                     if result is not None:
       
    74                         return result
       
    75                 try:
       
    76                     response = view_func(request, *args, **kwargs)
       
    77                 except Exception, e:
       
    78                     if hasattr(middleware, 'process_exception'):
       
    79                         result = middleware.process_exception(request, e)
       
    80                         if result is not None:
       
    81                             return result
       
    82                     raise
       
    83                 if hasattr(middleware, 'process_response'):
       
    84                     result = middleware.process_response(request, response)
       
    85                     if result is not None:
       
    86                         return result
       
    87                 return response
       
    88             return wraps(view_func, assigned=available_attrs(view_func))(_wrapped_view)
       
    89         return _decorator
       
    90     return _make_decorator