Loading django/template/loader_tags.py +33 −0 Original line number Diff line number Diff line import logging import posixpath from collections import defaultdict from django.utils import six Loading Loading @@ -249,6 +250,36 @@ def do_block(parser, token): return BlockNode(block_name, nodelist) def construct_relative_path(current_template_name, relative_name): """ Convert a relative path (starting with './' or '../') to the full template name based on the current_template_name. """ if not any(relative_name.startswith(x) for x in ["'./", "'../", '"./', '"../']): # relative_name is a variable or a literal that doesn't contain a # relative path. return relative_name new_name = posixpath.normpath( posixpath.join( posixpath.dirname(current_template_name.lstrip('/')), relative_name.strip('\'"') ) ) if new_name.startswith('../'): raise TemplateSyntaxError( "The relative path '%s' points outside the file hierarchy that " "template '%s' is in." % (relative_name, current_template_name) ) if current_template_name.lstrip('/') == new_name: raise TemplateSyntaxError( "The relative path '%s' was translated to template name '%s', the " "same template in which the tag appears." % (relative_name, current_template_name) ) return '"%s"' % new_name @register.tag('extends') def do_extends(parser, token): """ Loading @@ -263,6 +294,7 @@ def do_extends(parser, token): bits = token.split_contents() if len(bits) != 2: raise TemplateSyntaxError("'%s' takes one argument" % bits[0]) bits[1] = construct_relative_path(parser.origin.template_name, bits[1]) parent_name = parser.compile_filter(bits[1]) nodelist = parser.parse() if nodelist.get_nodes_by_type(ExtendsNode): Loading Loading @@ -313,5 +345,6 @@ def do_include(parser, token): options[option] = value isolated_context = options.get('only', False) namemap = options.get('with', {}) bits[1] = construct_relative_path(parser.origin.template_name, bits[1]) return IncludeNode(parser.compile_filter(bits[1]), extra_context=namemap, isolated_context=isolated_context) docs/ref/templates/builtins.txt +27 −0 Original line number Diff line number Diff line Loading @@ -212,6 +212,26 @@ This tag can be used in two ways: See :ref:`template-inheritance` for more information. A string argument may be a relative path starting with ``./`` or ``../``. For example, assume the following directory structure:: dir1/ template.html base2.html my/ base3.html base1.html In ``template.html``, the following paths would be valid:: {% extends "./base2.html" %} {% extends "../base1.html" %} {% extends "./my/base3.html" %} .. versionadded:: 1.10 The ability to use relative paths was added. .. templatetag:: filter ``filter`` Loading Loading @@ -663,6 +683,13 @@ This example includes the contents of the template ``"foo/bar.html"``:: {% include "foo/bar.html" %} A string argument may be a relative path starting with ``./`` or ``../`` as described in the :ttag:`extends` tag. .. versionadded:: 1.10 The ability to use a relative path was added. This example includes the contents of the template whose name is contained in the variable ``template_name``:: Loading docs/releases/1.10.txt +3 −0 Original line number Diff line number Diff line Loading @@ -451,6 +451,9 @@ Templates * The :func:`~django.template.context_processors.debug` context processor contains queries for all database aliases instead of only the default alias. * Added relative path support for string arguments of the :ttag:`extends` and :ttag:`include` template tags. Tests ~~~~~ Loading tests/template_tests/relative_templates/dir1/dir2/inc1.html 0 → 100644 +1 −0 Original line number Diff line number Diff line {% include "./../../three.html" %} tests/template_tests/relative_templates/dir1/dir2/inc2.html 0 → 100644 +1 −0 Original line number Diff line number Diff line {% include "./include_content.html" %} Loading
django/template/loader_tags.py +33 −0 Original line number Diff line number Diff line import logging import posixpath from collections import defaultdict from django.utils import six Loading Loading @@ -249,6 +250,36 @@ def do_block(parser, token): return BlockNode(block_name, nodelist) def construct_relative_path(current_template_name, relative_name): """ Convert a relative path (starting with './' or '../') to the full template name based on the current_template_name. """ if not any(relative_name.startswith(x) for x in ["'./", "'../", '"./', '"../']): # relative_name is a variable or a literal that doesn't contain a # relative path. return relative_name new_name = posixpath.normpath( posixpath.join( posixpath.dirname(current_template_name.lstrip('/')), relative_name.strip('\'"') ) ) if new_name.startswith('../'): raise TemplateSyntaxError( "The relative path '%s' points outside the file hierarchy that " "template '%s' is in." % (relative_name, current_template_name) ) if current_template_name.lstrip('/') == new_name: raise TemplateSyntaxError( "The relative path '%s' was translated to template name '%s', the " "same template in which the tag appears." % (relative_name, current_template_name) ) return '"%s"' % new_name @register.tag('extends') def do_extends(parser, token): """ Loading @@ -263,6 +294,7 @@ def do_extends(parser, token): bits = token.split_contents() if len(bits) != 2: raise TemplateSyntaxError("'%s' takes one argument" % bits[0]) bits[1] = construct_relative_path(parser.origin.template_name, bits[1]) parent_name = parser.compile_filter(bits[1]) nodelist = parser.parse() if nodelist.get_nodes_by_type(ExtendsNode): Loading Loading @@ -313,5 +345,6 @@ def do_include(parser, token): options[option] = value isolated_context = options.get('only', False) namemap = options.get('with', {}) bits[1] = construct_relative_path(parser.origin.template_name, bits[1]) return IncludeNode(parser.compile_filter(bits[1]), extra_context=namemap, isolated_context=isolated_context)
docs/ref/templates/builtins.txt +27 −0 Original line number Diff line number Diff line Loading @@ -212,6 +212,26 @@ This tag can be used in two ways: See :ref:`template-inheritance` for more information. A string argument may be a relative path starting with ``./`` or ``../``. For example, assume the following directory structure:: dir1/ template.html base2.html my/ base3.html base1.html In ``template.html``, the following paths would be valid:: {% extends "./base2.html" %} {% extends "../base1.html" %} {% extends "./my/base3.html" %} .. versionadded:: 1.10 The ability to use relative paths was added. .. templatetag:: filter ``filter`` Loading Loading @@ -663,6 +683,13 @@ This example includes the contents of the template ``"foo/bar.html"``:: {% include "foo/bar.html" %} A string argument may be a relative path starting with ``./`` or ``../`` as described in the :ttag:`extends` tag. .. versionadded:: 1.10 The ability to use a relative path was added. This example includes the contents of the template whose name is contained in the variable ``template_name``:: Loading
docs/releases/1.10.txt +3 −0 Original line number Diff line number Diff line Loading @@ -451,6 +451,9 @@ Templates * The :func:`~django.template.context_processors.debug` context processor contains queries for all database aliases instead of only the default alias. * Added relative path support for string arguments of the :ttag:`extends` and :ttag:`include` template tags. Tests ~~~~~ Loading
tests/template_tests/relative_templates/dir1/dir2/inc1.html 0 → 100644 +1 −0 Original line number Diff line number Diff line {% include "./../../three.html" %}
tests/template_tests/relative_templates/dir1/dir2/inc2.html 0 → 100644 +1 −0 Original line number Diff line number Diff line {% include "./include_content.html" %}