mirror of
				https://github.com/django/django.git
				synced 2025-10-29 00:26:07 +00:00 
			
		
		
		
	[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
			
			
This commit is contained in:
		| @@ -202,19 +202,19 @@ class Template(object): | |||||||
|  |  | ||||||
|     def render(self, context): |     def render(self, context): | ||||||
|         "Display stage -- can be called many times" |         "Display stage -- can be called many times" | ||||||
|         # Set engine attribute here to avoid changing the signature of either |         # Set context.template to the original template -- as opposed to | ||||||
|         # Context.__init__ or Node.render. The engine is set only on the first |         # extended or included templates -- during rendering. This may be | ||||||
|         # call to render. Further calls e.g. for includes don't override it. |         # used for accessing context.template.engine. | ||||||
|         toplevel_render = context.engine is None |         toplevel_render = context.template is None | ||||||
|         if toplevel_render: |         if toplevel_render: | ||||||
|             context.engine = self.engine |             context.template = self | ||||||
|         context.render_context.push() |         context.render_context.push() | ||||||
|         try: |         try: | ||||||
|             return self._render(context) |             return self._render(context) | ||||||
|         finally: |         finally: | ||||||
|             context.render_context.pop() |             context.render_context.pop() | ||||||
|             if toplevel_render: |             if toplevel_render: | ||||||
|                 context.engine = None |                 context.template = None | ||||||
|  |  | ||||||
|  |  | ||||||
| class Token(object): | class Token(object): | ||||||
| @@ -653,7 +653,7 @@ class FilterExpression(object): | |||||||
|                 if ignore_failures: |                 if ignore_failures: | ||||||
|                     obj = None |                     obj = None | ||||||
|                 else: |                 else: | ||||||
|                     string_if_invalid = context.engine.string_if_invalid |                     string_if_invalid = context.template.engine.string_if_invalid | ||||||
|                     if string_if_invalid: |                     if string_if_invalid: | ||||||
|                         if '%s' in string_if_invalid: |                         if '%s' in string_if_invalid: | ||||||
|                             return string_if_invalid % self.var |                             return string_if_invalid % self.var | ||||||
| @@ -845,7 +845,7 @@ class Variable(object): | |||||||
|                     if getattr(current, 'do_not_call_in_templates', False): |                     if getattr(current, 'do_not_call_in_templates', False): | ||||||
|                         pass |                         pass | ||||||
|                     elif getattr(current, 'alters_data', False): |                     elif getattr(current, 'alters_data', False): | ||||||
|                         current = context.engine.string_if_invalid |                         current = context.template.engine.string_if_invalid | ||||||
|                     else: |                     else: | ||||||
|                         try:  # method call (assuming no args required) |                         try:  # method call (assuming no args required) | ||||||
|                             current = current() |                             current = current() | ||||||
| @@ -853,12 +853,12 @@ class Variable(object): | |||||||
|                             try: |                             try: | ||||||
|                                 getcallargs(current) |                                 getcallargs(current) | ||||||
|                             except TypeError:  # arguments *were* required |                             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: |                             else: | ||||||
|                                 raise |                                 raise | ||||||
|         except Exception as e: |         except Exception as e: | ||||||
|             if getattr(e, 'silent_variable_failure', False): |             if getattr(e, 'silent_variable_failure', False): | ||||||
|                 current = context.engine.string_if_invalid |                 current = context.template.engine.string_if_invalid | ||||||
|             else: |             else: | ||||||
|                 raise |                 raise | ||||||
|  |  | ||||||
| @@ -1275,9 +1275,9 @@ class Library(object): | |||||||
|                         elif isinstance(getattr(file_name, 'template', None), Template): |                         elif isinstance(getattr(file_name, 'template', None), Template): | ||||||
|                             t = file_name.template |                             t = file_name.template | ||||||
|                         elif not isinstance(file_name, six.string_types) and is_iterable(file_name): |                         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: |                         else: | ||||||
|                             t = context.engine.get_template(file_name) |                             t = context.template.engine.get_template(file_name) | ||||||
|                         self.nodelist = t.nodelist |                         self.nodelist = t.nodelist | ||||||
|                     new_context = context.new(_dict) |                     new_context = context.new(_dict) | ||||||
|                     # Copy across the CSRF token, if present, because |                     # Copy across the CSRF token, if present, because | ||||||
|   | |||||||
| @@ -123,7 +123,7 @@ class Context(BaseContext): | |||||||
|     "A stack container for variable context" |     "A stack container for variable context" | ||||||
|     def __init__(self, dict_=None, autoescape=True, |     def __init__(self, dict_=None, autoescape=True, | ||||||
|             current_app=_current_app_undefined, |             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: |         if current_app is not _current_app_undefined: | ||||||
|             warnings.warn( |             warnings.warn( | ||||||
|                 "The current_app argument of Context is deprecated. Use " |                 "The current_app argument of Context is deprecated. Use " | ||||||
| @@ -133,8 +133,10 @@ class Context(BaseContext): | |||||||
|         self._current_app = current_app |         self._current_app = current_app | ||||||
|         self.use_l10n = use_l10n |         self.use_l10n = use_l10n | ||||||
|         self.use_tz = use_tz |         self.use_tz = use_tz | ||||||
|         self.engine = engine |  | ||||||
|         self.render_context = RenderContext() |         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_) |         super(Context, self).__init__(dict_) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
| @@ -192,11 +194,11 @@ class RequestContext(Context): | |||||||
|     """ |     """ | ||||||
|     def __init__(self, request, dict_=None, processors=None, |     def __init__(self, request, dict_=None, processors=None, | ||||||
|             current_app=_current_app_undefined, |             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 |         # current_app isn't passed here to avoid triggering the deprecation | ||||||
|         # warning in Context.__init__. |         # warning in Context.__init__. | ||||||
|         super(RequestContext, self).__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: |         if current_app is not _current_app_undefined: | ||||||
|             warnings.warn( |             warnings.warn( | ||||||
|                 "The current_app argument of RequestContext is deprecated. " |                 "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 = () if processors is None else tuple(processors) | ||||||
|         self._processors_index = len(self.dicts) |         self._processors_index = len(self.dicts) | ||||||
|         self.update({})         # placeholder for context processors output |         self.update({})         # placeholder for context processors output | ||||||
|         self.engine = engine    # re-run the setter in case engine is not None |  | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def engine(self): |     def template(self): | ||||||
|         return self._engine |         return self._template | ||||||
|  |  | ||||||
|     @engine.setter |     @template.setter | ||||||
|     def engine(self, engine): |     def template(self, template): | ||||||
|         self._engine = engine |         # 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 hasattr(self, '_processors_index'): | ||||||
|             if engine is None: |             if template is None: | ||||||
|                 # Unset context processors. |                 # Unset context processors. | ||||||
|                 self.dicts[self._processors_index] = {} |                 self.dicts[self._processors_index] = {} | ||||||
|             else: |             else: | ||||||
|                 # Set context processors for this engine. |                 # Set context processors for this engine. | ||||||
|  |                 processors = (template.engine.template_context_processors + | ||||||
|  |                               self._processors) | ||||||
|                 updates = {} |                 updates = {} | ||||||
|                 for processor in engine.template_context_processors + self._processors: |                 for processor in processors: | ||||||
|                     updates.update(processor(self.request)) |                     updates.update(processor(self.request)) | ||||||
|                 self.dicts[self._processors_index] = updates |                 self.dicts[self._processors_index] = updates | ||||||
|  |  | ||||||
|   | |||||||
| @@ -211,7 +211,7 @@ class ForNode(Node): | |||||||
|                     context[self.loopvars[0]] = item |                     context[self.loopvars[0]] = item | ||||||
|                 # In debug mode provide the source of the node which raised |                 # In debug mode provide the source of the node which raised | ||||||
|                 # the exception |                 # the exception | ||||||
|                 if context.engine.debug: |                 if context.template.engine.debug: | ||||||
|                     for node in self.nodelist_loop: |                     for node in self.nodelist_loop: | ||||||
|                         try: |                         try: | ||||||
|                             nodelist.append(node.render(context)) |                             nodelist.append(node.render(context)) | ||||||
| @@ -392,7 +392,7 @@ class SsiNode(Node): | |||||||
|     def render(self, context): |     def render(self, context): | ||||||
|         filepath = self.filepath.resolve(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: |             if settings.DEBUG: | ||||||
|                 return "[Didn't have permission to include file]" |                 return "[Didn't have permission to include file]" | ||||||
|             else: |             else: | ||||||
| @@ -404,7 +404,7 @@ class SsiNode(Node): | |||||||
|             output = '' |             output = '' | ||||||
|         if self.parsed: |         if self.parsed: | ||||||
|             try: |             try: | ||||||
|                 t = Template(output, name=filepath, engine=context.engine) |                 t = Template(output, name=filepath, engine=context.template.engine) | ||||||
|                 return t.render(context) |                 return t.render(context) | ||||||
|             except TemplateSyntaxError as e: |             except TemplateSyntaxError as e: | ||||||
|                 if settings.DEBUG: |                 if settings.DEBUG: | ||||||
|   | |||||||
| @@ -107,7 +107,7 @@ class ExtendsNode(Node): | |||||||
|         if isinstance(getattr(parent, 'template', None), Template): |         if isinstance(getattr(parent, 'template', None), Template): | ||||||
|             # parent is a django.template.backends.django.Template |             # parent is a django.template.backends.django.Template | ||||||
|             return parent.template |             return parent.template | ||||||
|         return context.engine.get_template(parent) |         return context.template.engine.get_template(parent) | ||||||
|  |  | ||||||
|     def render(self, context): |     def render(self, context): | ||||||
|         compiled_parent = self.get_parent(context) |         compiled_parent = self.get_parent(context) | ||||||
| @@ -148,7 +148,7 @@ class IncludeNode(Node): | |||||||
|             # Does this quack like a Template? |             # Does this quack like a Template? | ||||||
|             if not callable(getattr(template, 'render', None)): |             if not callable(getattr(template, 'render', None)): | ||||||
|                 # If not, we'll try get_template |                 # If not, we'll try get_template | ||||||
|                 template = context.engine.get_template(template) |                 template = context.template.engine.get_template(template) | ||||||
|             values = { |             values = { | ||||||
|                 name: var.resolve(context) |                 name: var.resolve(context) | ||||||
|                 for name, var in six.iteritems(self.extra_context) |                 for name, var in six.iteritems(self.extra_context) | ||||||
| @@ -158,7 +158,7 @@ class IncludeNode(Node): | |||||||
|             with context.push(**values): |             with context.push(**values): | ||||||
|                 return template.render(context) |                 return template.render(context) | ||||||
|         except Exception: |         except Exception: | ||||||
|             if context.engine.debug: |             if context.template.engine.debug: | ||||||
|                 raise |                 raise | ||||||
|             return '' |             return '' | ||||||
|  |  | ||||||
|   | |||||||
| @@ -149,7 +149,7 @@ class BlockTranslateNode(Node): | |||||||
|                 result = translation.pgettext(message_context, singular) |                 result = translation.pgettext(message_context, singular) | ||||||
|             else: |             else: | ||||||
|                 result = translation.ugettext(singular) |                 result = translation.ugettext(singular) | ||||||
|         default_value = context.engine.string_if_invalid |         default_value = context.template.engine.string_if_invalid | ||||||
|  |  | ||||||
|         def render_value(key): |         def render_value(key): | ||||||
|             if key in context: |             if key in context: | ||||||
|   | |||||||
| @@ -772,10 +772,11 @@ Notes: | |||||||
| * The ``render()`` method is where the work actually happens. | * The ``render()`` method is where the work actually happens. | ||||||
|  |  | ||||||
| * ``render()`` should generally fail silently, particularly in a production | * ``render()`` should generally fail silently, particularly in a production | ||||||
|   environment. In some cases however, particularly if ``context.engine.debug`` |   environment. In some cases however, particularly if | ||||||
|   is ``True``, this method may raise an exception to make debugging easier. |   ``context.template.engine.debug`` is ``True``, this method may raise an | ||||||
|   For example, several core tags raise ``django.template.TemplateSyntaxError`` |   exception to make debugging easier. For example, several core tags raise | ||||||
|   if they receive the wrong number or type of arguments. |   ``django.template.TemplateSyntaxError`` if they receive the wrong number or | ||||||
|  |   type of arguments. | ||||||
|  |  | ||||||
| Ultimately, this decoupling of compilation and rendering results in an | Ultimately, this decoupling of compilation and rendering results in an | ||||||
| efficient template system, because a template can render multiple contexts | efficient template system, because a template can render multiple contexts | ||||||
| @@ -811,16 +812,17 @@ This is not a very common situation, but it's useful if you're rendering a | |||||||
| template yourself. For example:: | template yourself. For example:: | ||||||
|  |  | ||||||
|     def render(self, context): |     def render(self, context): | ||||||
|         t = context.engine.get_template('small_fragment.html') |         t = context.template.engine.get_template('small_fragment.html') | ||||||
|         return t.render(Context({'var': obj}, autoescape=context.autoescape)) |         return t.render(Context({'var': obj}, autoescape=context.autoescape)) | ||||||
|  |  | ||||||
| .. versionchanged:: 1.8 | .. versionchanged:: 1.8 | ||||||
|  |  | ||||||
|     The ``engine`` attribute of ``Context`` objects was added in Django 1.8. |     The ``template`` attribute of ``Context`` objects was added in Django 1.8. | ||||||
|     :meth:`context.engine.get_template <django.template.Engine.get_template>` |     :meth:`context.template.engine.get_template | ||||||
|     must be used instead of :func:`django.template.loader.get_template` |     <django.template.Engine.get_template>` must be used instead of | ||||||
|     because the latter now returns a wrapper whose ``render`` method doesn't |     :func:`django.template.loader.get_template` because the latter now returns | ||||||
|     accept a :class:`~django.template.Context`. |     a wrapper whose ``render`` method doesn't accept a | ||||||
|  |     :class:`~django.template.Context`. | ||||||
|  |  | ||||||
| If we had neglected to pass in the current ``context.autoescape`` value to our | If we had neglected to pass in the current ``context.autoescape`` value to our | ||||||
| new ``Context`` in this example, the results would have *always* been | new ``Context`` in this example, the results would have *always* been | ||||||
|   | |||||||
| @@ -162,7 +162,7 @@ instance in the ``render()`` method of a template tag, you can use the current | |||||||
|  |  | ||||||
| You can write:: | You can write:: | ||||||
|  |  | ||||||
|     template = context.engine.get_template('included.html') |     template = context.template.engine.get_template('included.html') | ||||||
|  |  | ||||||
| This will load the template with the current engine without triggering the | This will load the template with the current engine without triggering the | ||||||
| multiple template engines machinery, which is usually the desired behavior. | multiple template engines machinery, which is usually the desired behavior. | ||||||
| @@ -201,7 +201,7 @@ APIs. The multiple template engines machinery isn't involved here. | |||||||
| Finally, if you have access to the current context, you can use the same trick | Finally, if you have access to the current context, you can use the same trick | ||||||
| as above:: | as above:: | ||||||
|  |  | ||||||
|     template = context.engine.from_string(template_code) |     template = context.template.engine.from_string(template_code) | ||||||
|  |  | ||||||
| ``Template()`` | ``Template()`` | ||||||
| ============== | ============== | ||||||
|   | |||||||
| @@ -516,9 +516,6 @@ class RequestContextTests(unittest.TestCase): | |||||||
|         self.assertEqual(len(ctx.dicts), 3) |         self.assertEqual(len(ctx.dicts), 3) | ||||||
|  |  | ||||||
|     def test_context_comparable(self): |     def test_context_comparable(self): | ||||||
|         # Create an engine without any context processors. |  | ||||||
|         engine = Engine() |  | ||||||
|  |  | ||||||
|         test_data = {'x': 'y', 'v': 'z', 'd': {'o': object, 'a': 'b'}} |         test_data = {'x': 'y', 'v': 'z', 'd': {'o': object, 'a': 'b'}} | ||||||
|  |  | ||||||
|         # test comparing RequestContext to prevent problems if somebody |         # test comparing RequestContext to prevent problems if somebody | ||||||
| @@ -526,8 +523,8 @@ class RequestContextTests(unittest.TestCase): | |||||||
|         request = RequestFactory().get('/') |         request = RequestFactory().get('/') | ||||||
|  |  | ||||||
|         self.assertEqual( |         self.assertEqual( | ||||||
|             RequestContext(request, dict_=test_data, engine=engine), |             RequestContext(request, dict_=test_data), | ||||||
|             RequestContext(request, dict_=test_data, engine=engine)) |             RequestContext(request, dict_=test_data)) | ||||||
|  |  | ||||||
|  |  | ||||||
| @ignore_warnings(category=RemovedInDjango20Warning) | @ignore_warnings(category=RemovedInDjango20Warning) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user