diff options
| author | Aymeric Augustin <aymeric.augustin@m4x.org> | 2015-02-19 23:20:27 +0100 |
|---|---|---|
| committer | Aymeric Augustin <aymeric.augustin@m4x.org> | 2015-02-20 22:28:24 +0100 |
| commit | e4e140c49b1bd3dc8ae11900a0089ec908483cf0 (patch) | |
| tree | 7cdaf69e99ea9cb63daf9543b1df1bbbeea587f5 | |
| parent | 88e6fbb2e341657cb5365b9b78fb44e3c7065d2d (diff) | |
[1.8.x] Removed a non-obvious side-effect of assigning Context.template.
Explicit is better than implicit.
Backport of 51b606f from master
| -rw-r--r-- | django/template/base.py | 14 | ||||
| -rw-r--r-- | django/template/context.py | 55 |
2 files changed, 37 insertions, 32 deletions
diff --git a/django/template/base.py b/django/template/base.py index 76f77fc793..0c57050313 100644 --- a/django/template/base.py +++ b/django/template/base.py @@ -202,19 +202,15 @@ class Template(object): def render(self, context): "Display stage -- can be called many times" - # Set context.template to the original template -- as opposed to - # extended or included templates -- during rendering. This may be - # used for accessing context.template.engine. - toplevel_render = context.template is None - if toplevel_render: - context.template = self context.render_context.push() try: - return self._render(context) + if context.template is None: + with context.bind_template(self): + return self._render(context) + else: + return self._render(context) finally: context.render_context.pop() - if toplevel_render: - context.template = None class Token(object): diff --git a/django/template/context.py b/django/template/context.py index b4983d1909..af4fb8853b 100644 --- a/django/template/context.py +++ b/django/template/context.py @@ -1,4 +1,5 @@ import warnings +from contextlib import contextmanager from copy import copy from django.utils.deprecation import RemovedInDjango20Warning @@ -134,8 +135,8 @@ class Context(BaseContext): self.use_l10n = use_l10n self.use_tz = use_tz self.render_context = RenderContext() - # Set to the original template during rendering -- as opposed to - # extended or included templates + # Set to the original template -- as opposed to extended or included + # templates -- during rendering, see bind_template. self.template = None super(Context, self).__init__(dict_) @@ -143,6 +144,16 @@ class Context(BaseContext): def current_app(self): return None if self._current_app is _current_app_undefined else self._current_app + @contextmanager + def bind_template(self, template): + if self.template is not None: + raise RuntimeError("Context is already bound to a template") + self.template = template + try: + yield + finally: + self.template = None + def __copy__(self): duplicate = super(Context, self).__copy__() duplicate.render_context = copy(self.render_context) @@ -210,28 +221,26 @@ class RequestContext(Context): self._processors_index = len(self.dicts) self.update({}) # placeholder for context processors output - @property - def template(self): - return self._template + @contextmanager + def bind_template(self, template): + if self.template is not None: + raise RuntimeError("Context is already bound to a template") + + self.template = template + # Set context processors according to the template engine's settings. + processors = (template.engine.template_context_processors + + self._processors) + updates = {} + for processor in processors: + updates.update(processor(self.request)) + self.dicts[self._processors_index] = updates - @template.setter - def template(self, template): - # Execute context processors when Template.render(self, context) sets - # context.template = self. Until then, since the context isn't tied to - # an engine, it has no way to know which context processors to apply. - self._template = template - if hasattr(self, '_processors_index'): - if template is None: - # Unset context processors. - self.dicts[self._processors_index] = {} - else: - # Set context processors for this engine. - processors = (template.engine.template_context_processors + - self._processors) - updates = {} - for processor in processors: - updates.update(processor(self.request)) - self.dicts[self._processors_index] = updates + try: + yield + finally: + self.template = None + # Unset context processors. + self.dicts[self._processors_index] = {} def new(self, values=None): new_context = super(RequestContext, self).new(values) |
