From cc4effba0bf07fbcb4dcc0074af969e698b6cc75 Mon Sep 17 00:00:00 2001 From: Aymeric Augustin Date: Tue, 17 Feb 2015 22:49:59 +0100 Subject: [1.8.x] Set context.template instead of context.engine while rendering. This opens more possibilities, like accessing context.template.origin. It also follows the chain of objects instead of following a shortcut. Backport of 1bfcc95 from master --- django/template/base.py | 24 ++++++++++++------------ django/template/context.py | 32 +++++++++++++++++++------------- django/template/defaulttags.py | 6 +++--- django/template/loader_tags.py | 6 +++--- django/templatetags/i18n.py | 2 +- 5 files changed, 38 insertions(+), 32 deletions(-) (limited to 'django') diff --git a/django/template/base.py b/django/template/base.py index b9fd47625b..76f77fc793 100644 --- a/django/template/base.py +++ b/django/template/base.py @@ -202,19 +202,19 @@ class Template(object): def render(self, context): "Display stage -- can be called many times" - # Set engine attribute here to avoid changing the signature of either - # Context.__init__ or Node.render. The engine is set only on the first - # call to render. Further calls e.g. for includes don't override it. - toplevel_render = context.engine is None + # 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.engine = self.engine + context.template = self context.render_context.push() try: return self._render(context) finally: context.render_context.pop() if toplevel_render: - context.engine = None + context.template = None class Token(object): @@ -653,7 +653,7 @@ class FilterExpression(object): if ignore_failures: obj = None else: - string_if_invalid = context.engine.string_if_invalid + string_if_invalid = context.template.engine.string_if_invalid if string_if_invalid: if '%s' in string_if_invalid: return string_if_invalid % self.var @@ -845,7 +845,7 @@ class Variable(object): if getattr(current, 'do_not_call_in_templates', False): pass elif getattr(current, 'alters_data', False): - current = context.engine.string_if_invalid + current = context.template.engine.string_if_invalid else: try: # method call (assuming no args required) current = current() @@ -853,12 +853,12 @@ class Variable(object): try: getcallargs(current) except TypeError: # arguments *were* required - current = context.engine.string_if_invalid # invalid method call + current = context.template.engine.string_if_invalid # invalid method call else: raise except Exception as e: if getattr(e, 'silent_variable_failure', False): - current = context.engine.string_if_invalid + current = context.template.engine.string_if_invalid else: raise @@ -1275,9 +1275,9 @@ class Library(object): elif isinstance(getattr(file_name, 'template', None), Template): t = file_name.template elif not isinstance(file_name, six.string_types) and is_iterable(file_name): - t = context.engine.select_template(file_name) + t = context.template.engine.select_template(file_name) else: - t = context.engine.get_template(file_name) + t = context.template.engine.get_template(file_name) self.nodelist = t.nodelist new_context = context.new(_dict) # Copy across the CSRF token, if present, because diff --git a/django/template/context.py b/django/template/context.py index 01d21a159a..b4983d1909 100644 --- a/django/template/context.py +++ b/django/template/context.py @@ -123,7 +123,7 @@ class Context(BaseContext): "A stack container for variable context" def __init__(self, dict_=None, autoescape=True, current_app=_current_app_undefined, - use_l10n=None, use_tz=None, engine=None): + use_l10n=None, use_tz=None): if current_app is not _current_app_undefined: warnings.warn( "The current_app argument of Context is deprecated. Use " @@ -133,8 +133,10 @@ class Context(BaseContext): self._current_app = current_app self.use_l10n = use_l10n self.use_tz = use_tz - self.engine = engine self.render_context = RenderContext() + # Set to the original template during rendering -- as opposed to + # extended or included templates + self.template = None super(Context, self).__init__(dict_) @property @@ -192,11 +194,11 @@ class RequestContext(Context): """ def __init__(self, request, dict_=None, processors=None, current_app=_current_app_undefined, - use_l10n=None, use_tz=None, engine=None): + use_l10n=None, use_tz=None): # current_app isn't passed here to avoid triggering the deprecation # warning in Context.__init__. super(RequestContext, self).__init__( - dict_, use_l10n=use_l10n, use_tz=use_tz, engine=engine) + dict_, use_l10n=use_l10n, use_tz=use_tz) if current_app is not _current_app_undefined: warnings.warn( "The current_app argument of RequestContext is deprecated. " @@ -207,23 +209,27 @@ class RequestContext(Context): self._processors = () if processors is None else tuple(processors) self._processors_index = len(self.dicts) self.update({}) # placeholder for context processors output - self.engine = engine # re-run the setter in case engine is not None @property - def engine(self): - return self._engine - - @engine.setter - def engine(self, engine): - self._engine = engine + def template(self): + return self._template + + @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 engine is None: + 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 engine.template_context_processors + self._processors: + for processor in processors: updates.update(processor(self.request)) self.dicts[self._processors_index] = updates diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 0dc6735ad6..fc8baf9611 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -211,7 +211,7 @@ class ForNode(Node): context[self.loopvars[0]] = item # In debug mode provide the source of the node which raised # the exception - if context.engine.debug: + if context.template.engine.debug: for node in self.nodelist_loop: try: nodelist.append(node.render(context)) @@ -392,7 +392,7 @@ class SsiNode(Node): def render(self, context): filepath = self.filepath.resolve(context) - if not include_is_allowed(filepath, context.engine.allowed_include_roots): + if not include_is_allowed(filepath, context.template.engine.allowed_include_roots): if settings.DEBUG: return "[Didn't have permission to include file]" else: @@ -404,7 +404,7 @@ class SsiNode(Node): output = '' if self.parsed: try: - t = Template(output, name=filepath, engine=context.engine) + t = Template(output, name=filepath, engine=context.template.engine) return t.render(context) except TemplateSyntaxError as e: if settings.DEBUG: diff --git a/django/template/loader_tags.py b/django/template/loader_tags.py index e6635258a7..398914b6b7 100644 --- a/django/template/loader_tags.py +++ b/django/template/loader_tags.py @@ -107,7 +107,7 @@ class ExtendsNode(Node): if isinstance(getattr(parent, 'template', None), Template): # parent is a django.template.backends.django.Template return parent.template - return context.engine.get_template(parent) + return context.template.engine.get_template(parent) def render(self, context): compiled_parent = self.get_parent(context) @@ -148,7 +148,7 @@ class IncludeNode(Node): # Does this quack like a Template? if not callable(getattr(template, 'render', None)): # If not, we'll try get_template - template = context.engine.get_template(template) + template = context.template.engine.get_template(template) values = { name: var.resolve(context) for name, var in six.iteritems(self.extra_context) @@ -158,7 +158,7 @@ class IncludeNode(Node): with context.push(**values): return template.render(context) except Exception: - if context.engine.debug: + if context.template.engine.debug: raise return '' diff --git a/django/templatetags/i18n.py b/django/templatetags/i18n.py index b30d6afa95..8c6746c680 100644 --- a/django/templatetags/i18n.py +++ b/django/templatetags/i18n.py @@ -149,7 +149,7 @@ class BlockTranslateNode(Node): result = translation.pgettext(message_context, singular) else: result = translation.ugettext(singular) - default_value = context.engine.string_if_invalid + default_value = context.template.engine.string_if_invalid def render_value(key): if key in context: -- cgit v1.3