Commit aec4f975 authored by Vitaly Bogomolov's avatar Vitaly Bogomolov Committed by Tim Graham
Browse files

Fixed #26402 -- Added relative path support in include/extends template tags.

parent ad403ffa
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
import logging
import posixpath
from collections import defaultdict

from django.utils import six
@@ -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):
    """
@@ -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):
@@ -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)
+27 −0
Original line number Diff line number Diff line
@@ -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``
@@ -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``::

+3 −0
Original line number Diff line number Diff line
@@ -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
~~~~~

+1 −0
Original line number Diff line number Diff line
{% include "./../../three.html" %}
+1 −0
Original line number Diff line number Diff line
{% include "./include_content.html" %}
Loading