web/lib/django/utils/decorators.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
     1 "Functions that help with dynamically creating decorators for views."
     1 "Functions that help with dynamically creating decorators for views."
     2 
     2 
     3 import types
     3 import types
     4 try:
     4 try:
     5     from functools import wraps
     5     from functools import wraps, update_wrapper, WRAPPER_ASSIGNMENTS
     6 except ImportError:
     6 except ImportError:
     7     from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.
     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_dec(%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 
     8 
    44 
     9 def decorator_from_middleware(middleware_class):
    45 def decorator_from_middleware(middleware_class):
    10     """
    46     """
    11     Given a middleware class (not an instance), returns a view decorator. This
    47     Given a middleware class (not an instance), returns a view decorator. This
    12     lets you use middleware functionality on a per-view basis.
    48     lets you use middleware functionality on a per-view basis. The middleware
       
    49     is created with no params passed.
    13     """
    50     """
    14     def _decorator_from_middleware(*args, **kwargs):
    51     return make_middleware_decorator(middleware_class)()
    15         # For historical reasons, these "decorators" are also called as
       
    16         # dec(func, *args) instead of dec(*args)(func). We handle both forms
       
    17         # for backwards compatibility.
       
    18         has_func = True
       
    19         try:
       
    20             view_func = kwargs.pop('view_func')
       
    21         except KeyError:
       
    22             if len(args):
       
    23                 view_func, args = args[0], args[1:]
       
    24             else:
       
    25                 has_func = False
       
    26         if not (has_func and isinstance(view_func, types.FunctionType)):
       
    27             # We are being called as a decorator.
       
    28             if has_func:
       
    29                 args = (view_func,) + args
       
    30             middleware = middleware_class(*args, **kwargs)
       
    31 
    52 
    32             def decorator_func(fn):
    53 def available_attrs(fn):
    33                 return _decorator_from_middleware(fn, *args, **kwargs)
    54     """
    34             return decorator_func
    55     Return the list of functools-wrappable attributes on a callable.
       
    56     This is required as a workaround for http://bugs.python.org/issue3445.
       
    57     """
       
    58     return tuple(a for a in WRAPPER_ASSIGNMENTS if hasattr(fn, a))
    35 
    59 
    36         middleware = middleware_class(*args, **kwargs)
    60 def make_middleware_decorator(middleware_class):
    37 
    61     def _make_decorator(*m_args, **m_kwargs):
    38         def _wrapped_view(request, *args, **kwargs):
    62         middleware = middleware_class(*m_args, **m_kwargs)
    39             if hasattr(middleware, 'process_request'):
    63         def _decorator(view_func):
    40                 result = middleware.process_request(request)
    64             def _wrapped_view(request, *args, **kwargs):
    41                 if result is not None:
    65                 if hasattr(middleware, 'process_request'):
    42                     return result
    66                     result = middleware.process_request(request)
    43             if hasattr(middleware, 'process_view'):
       
    44                 result = middleware.process_view(request, view_func, args, kwargs)
       
    45                 if result is not None:
       
    46                     return result
       
    47             try:
       
    48                 response = view_func(request, *args, **kwargs)
       
    49             except Exception, e:
       
    50                 if hasattr(middleware, 'process_exception'):
       
    51                     result = middleware.process_exception(request, e)
       
    52                     if result is not None:
    67                     if result is not None:
    53                         return result
    68                         return result
    54                 raise
    69                 if hasattr(middleware, 'process_view'):
    55             if hasattr(middleware, 'process_response'):
    70                     result = middleware.process_view(request, view_func, args, kwargs)
    56                 result = middleware.process_response(request, response)
    71                     if result is not None:
    57                 if result is not None:
    72                         return result
    58                     return result
    73                 try:
    59             return response
    74                     response = view_func(request, *args, **kwargs)
    60         return wraps(view_func)(_wrapped_view)
    75                 except Exception, e:
    61     return _decorator_from_middleware
    76                     if hasattr(middleware, 'process_exception'):
       
    77                         result = middleware.process_exception(request, e)
       
    78                         if result is not None:
       
    79                             return result
       
    80                     raise
       
    81                 if hasattr(middleware, 'process_response'):
       
    82                     result = middleware.process_response(request, response)
       
    83                     if result is not None:
       
    84                         return result
       
    85                 return response
       
    86             return wraps(view_func, assigned=available_attrs(view_func))(_wrapped_view)
       
    87         return _decorator
       
    88     return _make_decorator