1 from django.core.exceptions import ImproperlyConfigured |
1 from django.core.exceptions import ImproperlyConfigured |
2 from django.utils.importlib import import_module |
2 from django.utils.importlib import import_module |
3 |
3 |
|
4 # Cache of actual callables. |
4 _standard_context_processors = None |
5 _standard_context_processors = None |
|
6 # We need the CSRF processor no matter what the user has in their settings, |
|
7 # because otherwise it is a security vulnerability, and we can't afford to leave |
|
8 # this to human error or failure to read migration instructions. |
|
9 _builtin_context_processors = ('django.core.context_processors.csrf',) |
5 |
10 |
6 class ContextPopException(Exception): |
11 class ContextPopException(Exception): |
7 "pop() has been called more times than push()" |
12 "pop() has been called more times than push()" |
8 pass |
13 pass |
9 |
14 |
10 class Context(object): |
15 class BaseContext(object): |
11 "A stack container for variable context" |
16 def __init__(self, dict_=None): |
12 def __init__(self, dict_=None, autoescape=True, current_app=None): |
|
13 dict_ = dict_ or {} |
17 dict_ = dict_ or {} |
14 self.dicts = [dict_] |
18 self.dicts = [dict_] |
15 self.autoescape = autoescape |
|
16 self.current_app = current_app |
|
17 |
19 |
18 def __repr__(self): |
20 def __repr__(self): |
19 return repr(self.dicts) |
21 return repr(self.dicts) |
20 |
22 |
21 def __iter__(self): |
23 def __iter__(self): |
22 for d in self.dicts: |
24 for d in reversed(self.dicts): |
23 yield d |
25 yield d |
24 |
26 |
25 def push(self): |
27 def push(self): |
26 d = {} |
28 d = {} |
27 self.dicts = [d] + self.dicts |
29 self.dicts.append(d) |
28 return d |
30 return d |
29 |
31 |
30 def pop(self): |
32 def pop(self): |
31 if len(self.dicts) == 1: |
33 if len(self.dicts) == 1: |
32 raise ContextPopException |
34 raise ContextPopException |
33 return self.dicts.pop(0) |
35 return self.dicts.pop() |
34 |
36 |
35 def __setitem__(self, key, value): |
37 def __setitem__(self, key, value): |
36 "Set a variable in the current context" |
38 "Set a variable in the current context" |
37 self.dicts[0][key] = value |
39 self.dicts[-1][key] = value |
38 |
40 |
39 def __getitem__(self, key): |
41 def __getitem__(self, key): |
40 "Get a variable's value, starting at the current context and going upward" |
42 "Get a variable's value, starting at the current context and going upward" |
41 for d in self.dicts: |
43 for d in reversed(self.dicts): |
42 if key in d: |
44 if key in d: |
43 return d[key] |
45 return d[key] |
44 raise KeyError(key) |
46 raise KeyError(key) |
45 |
47 |
46 def __delitem__(self, key): |
48 def __delitem__(self, key): |
47 "Delete a variable from the current context" |
49 "Delete a variable from the current context" |
48 del self.dicts[0][key] |
50 del self.dicts[-1][key] |
49 |
51 |
50 def has_key(self, key): |
52 def has_key(self, key): |
51 for d in self.dicts: |
53 for d in self.dicts: |
52 if key in d: |
54 if key in d: |
53 return True |
55 return True |
54 return False |
56 return False |
55 |
57 |
56 __contains__ = has_key |
58 def __contains__(self, key): |
|
59 return self.has_key(key) |
57 |
60 |
58 def get(self, key, otherwise=None): |
61 def get(self, key, otherwise=None): |
59 for d in self.dicts: |
62 for d in reversed(self.dicts): |
60 if key in d: |
63 if key in d: |
61 return d[key] |
64 return d[key] |
62 return otherwise |
65 return otherwise |
|
66 |
|
67 class Context(BaseContext): |
|
68 "A stack container for variable context" |
|
69 def __init__(self, dict_=None, autoescape=True, current_app=None): |
|
70 self.autoescape = autoescape |
|
71 self.current_app = current_app |
|
72 self.render_context = RenderContext() |
|
73 super(Context, self).__init__(dict_) |
63 |
74 |
64 def update(self, other_dict): |
75 def update(self, other_dict): |
65 "Like dict.update(). Pushes an entire dictionary's keys and values onto the context." |
76 "Like dict.update(). Pushes an entire dictionary's keys and values onto the context." |
66 if not hasattr(other_dict, '__getitem__'): |
77 if not hasattr(other_dict, '__getitem__'): |
67 raise TypeError('other_dict must be a mapping (dictionary-like) object.') |
78 raise TypeError('other_dict must be a mapping (dictionary-like) object.') |
68 self.dicts = [other_dict] + self.dicts |
79 self.dicts.append(other_dict) |
69 return other_dict |
80 return other_dict |
|
81 |
|
82 class RenderContext(BaseContext): |
|
83 """ |
|
84 A stack container for storing Template state. |
|
85 |
|
86 RenderContext simplifies the implementation of template Nodes by providing a |
|
87 safe place to store state between invocations of a node's `render` method. |
|
88 |
|
89 The RenderContext also provides scoping rules that are more sensible for |
|
90 'template local' variables. The render context stack is pushed before each |
|
91 template is rendered, creating a fresh scope with nothing in it. Name |
|
92 resolution fails if a variable is not found at the top of the RequestContext |
|
93 stack. Thus, variables are local to a specific template and don't affect the |
|
94 rendering of other templates as they would if they were stored in the normal |
|
95 template context. |
|
96 """ |
|
97 def __iter__(self): |
|
98 for d in self.dicts[-1]: |
|
99 yield d |
|
100 |
|
101 def has_key(self, key): |
|
102 return key in self.dicts[-1] |
|
103 |
|
104 def get(self, key, otherwise=None): |
|
105 d = self.dicts[-1] |
|
106 if key in d: |
|
107 return d[key] |
|
108 return otherwise |
70 |
109 |
71 # This is a function rather than module-level procedural code because we only |
110 # This is a function rather than module-level procedural code because we only |
72 # want it to execute if somebody uses RequestContext. |
111 # want it to execute if somebody uses RequestContext. |
73 def get_standard_processors(): |
112 def get_standard_processors(): |
74 from django.conf import settings |
113 from django.conf import settings |
75 global _standard_context_processors |
114 global _standard_context_processors |
76 if _standard_context_processors is None: |
115 if _standard_context_processors is None: |
77 processors = [] |
116 processors = [] |
78 for path in settings.TEMPLATE_CONTEXT_PROCESSORS: |
117 collect = [] |
|
118 collect.extend(_builtin_context_processors) |
|
119 collect.extend(settings.TEMPLATE_CONTEXT_PROCESSORS) |
|
120 for path in collect: |
79 i = path.rfind('.') |
121 i = path.rfind('.') |
80 module, attr = path[:i], path[i+1:] |
122 module, attr = path[:i], path[i+1:] |
81 try: |
123 try: |
82 mod = import_module(module) |
124 mod = import_module(module) |
83 except ImportError, e: |
125 except ImportError, e: |