|
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 |