Просмотр исходного кода

Switched {% cycle %} and {% firstof %} tags to auto-escape their variables per deprecation timeline.

refs #17906.
Tim Graham 11 лет назад
Родитель
Сommit
1ea44a3abd

+ 7 - 28
django/template/defaulttags.py

@@ -17,7 +17,6 @@ from django.template.base import (Node, NodeList, Template, Context, Library,
     render_value_in_context)
 from django.template.smartif import IfParser, Literal
 from django.template.defaultfilters import date
-from django.utils.deprecation import RemovedInDjango18Warning
 from django.utils.encoding import force_text, smart_text
 from django.utils.safestring import mark_safe
 from django.utils.html import format_html
@@ -65,11 +64,10 @@ class CsrfTokenNode(Node):
 
 
 class CycleNode(Node):
-    def __init__(self, cyclevars, variable_name=None, silent=False, escape=False):
+    def __init__(self, cyclevars, variable_name=None, silent=False):
         self.cyclevars = cyclevars
         self.variable_name = variable_name
         self.silent = silent
-        self.escape = escape        # only while the "future" version exists
 
     def render(self, context):
         if self not in context.render_context:
@@ -81,8 +79,6 @@ class CycleNode(Node):
             context[self.variable_name] = value
         if self.silent:
             return ''
-        if not self.escape:
-            value = mark_safe(value)
         return render_value_in_context(value, context)
 
 
@@ -107,16 +103,13 @@ class FilterNode(Node):
 
 
 class FirstOfNode(Node):
-    def __init__(self, variables, escape=False):
+    def __init__(self, variables):
         self.vars = variables
-        self.escape = escape        # only while the "future" version exists
 
     def render(self, context):
         for var in self.vars:
             value = var.resolve(context, True)
             if value:
-                if not self.escape:
-                    value = mark_safe(value)
                 return render_value_in_context(value, context)
         return ''
 
@@ -554,7 +547,7 @@ def comment(parser, token):
 
 
 @register.tag
-def cycle(parser, token, escape=False):
+def cycle(parser, token):
     """
     Cycles among the given strings each time this tag is encountered.
 
@@ -587,13 +580,6 @@ def cycle(parser, token, escape=False):
         {% endfor %}
 
     """
-    if not escape:
-        warnings.warn(
-            "'The `cycle` template tag is changing to escape its arguments; "
-            "the non-autoescaping version is deprecated. Load it "
-            "from the `future` tag library to start using the new behavior.",
-            RemovedInDjango18Warning, stacklevel=2)
-
     # Note: This returns the exact same node on each {% cycle name %} call;
     # that is, the node object returned from {% cycle a b c as name %} and the
     # one returned from {% cycle name %} are the exact same object. This
@@ -640,13 +626,13 @@ def cycle(parser, token, escape=False):
     if as_form:
         name = args[-1]
         values = [parser.compile_filter(arg) for arg in args[1:-2]]
-        node = CycleNode(values, name, silent=silent, escape=escape)
+        node = CycleNode(values, name, silent=silent)
         if not hasattr(parser, '_namedCycleNodes'):
             parser._namedCycleNodes = {}
         parser._namedCycleNodes[name] = node
     else:
         values = [parser.compile_filter(arg) for arg in args[1:]]
-        node = CycleNode(values, escape=escape)
+        node = CycleNode(values)
     return node
 
 
@@ -701,7 +687,7 @@ def do_filter(parser, token):
 
 
 @register.tag
-def firstof(parser, token, escape=False):
+def firstof(parser, token):
     """
     Outputs the first variable passed that is not False, without escaping.
 
@@ -735,17 +721,10 @@ def firstof(parser, token, escape=False):
         {% endfilter %}
 
     """
-    if not escape:
-        warnings.warn(
-            "'The `firstof` template tag is changing to escape its arguments; "
-            "the non-autoescaping version is deprecated. Load it "
-            "from the `future` tag library to start using the new behavior.",
-            RemovedInDjango18Warning, stacklevel=2)
-
     bits = token.split_contents()[1:]
     if len(bits) < 1:
         raise TemplateSyntaxError("'firstof' statement requires at least one argument")
-    return FirstOfNode([parser.compile_filter(bit) for bit in bits], escape=escape)
+    return FirstOfNode([parser.compile_filter(bit) for bit in bits])
 
 
 @register.tag('for')

+ 6 - 2
django/templatetags/future.py

@@ -29,6 +29,8 @@ def url(parser, token):
 def cycle(parser, token):
     """
     This is the future version of `cycle` with auto-escaping.
+    The deprecation is now complete and this version is no different
+    from the non-future version so this can be deprecated (#22306)
 
     By default all strings are escaped.
 
@@ -42,13 +44,15 @@ def cycle(parser, token):
 
         {% cycle var1 var2|safe var3|safe  as somecycle %}
     """
-    return defaulttags.cycle(parser, token, escape=True)
+    return defaulttags.cycle(parser, token)
 
 
 @register.tag
 def firstof(parser, token):
     """
     This is the future version of `firstof` with auto-escaping.
+    The deprecation is now complete and this version is no different
+    from the non-future version so this can be deprecated (#22306)
 
     This is equivalent to::
 
@@ -71,4 +75,4 @@ def firstof(parser, token):
         {% firstof var1 var2|safe var3 "<strong>fallback value</strong>"|safe %}
 
     """
-    return defaulttags.firstof(parser, token, escape=True)
+    return defaulttags.firstof(parser, token)

+ 11 - 47
docs/ref/templates/builtins.txt

@@ -102,13 +102,11 @@ this::
         </tr>
     {% endfor %}
 
-Note that the variables included in the cycle will not be escaped. Any HTML or
-Javascript code contained in the printed variable will be rendered as-is, which
-could potentially lead to security issues. So either make sure that you trust
-their values or use explicit escaping like this::
+Variables included in the cycle will be escaped.  You can disable auto-escaping
+with::
 
     {% for o in some_list %}
-        <tr class="{% filter force_escape %}{% cycle rowvalue1 rowvalue2 %}{% endfilter %}">
+        <tr class="{% autoescape off %}{% cycle rowvalue1 rowvalue2 %}{% endautoescape
             ...
         </tr>
     {% endfor %}
@@ -196,21 +194,6 @@ In this syntax, each value gets interpreted as a literal string, and there's no
 way to specify variable values. Or literal commas. Or spaces. Did we mention
 you shouldn't use this syntax in any new projects?
 
-.. versionchanged:: 1.6
-
-To improve safety, future versions of ``cycle`` will automatically escape
-their output. You're encouraged to activate this behavior by loading
-``cycle`` from the ``future`` template library::
-
-    {% load cycle from future %}
-
-When using the ``future`` version, you can disable auto-escaping with::
-
-    {% for o in some_list %}
-        <tr class="{% autoescape off %}{% cycle rowvalue1 rowvalue2 %}{% endautoescape %}">
-            ...
-        </tr>
-    {% endfor %}
 
 .. templatetag:: debug
 
@@ -268,10 +251,8 @@ Sample usage::
 firstof
 ^^^^^^^
 
-Outputs the first argument variable that is not False. This tag does *not*
-auto-escape variable values.
-
-Outputs nothing if all the passed variables are False.
+Outputs the first argument variable that is not ``False``. Outputs nothing if
+all the passed variables are ``False``.
 
 Sample usage::
 
@@ -292,32 +273,15 @@ passed variables are False::
 
     {% firstof var1 var2 var3 "fallback value" %}
 
-Note that currently the variables included in the firstof tag will not be
-escaped. Any HTML or Javascript code contained in the printed variable will be
-rendered as-is, which could potentially lead to security issues. If you need
-to escape the variables in the firstof tag, you must do so explicitly::
+This tag auto-escapes variable values. You can disable auto-escaping with::
 
-    {% filter force_escape %}
-        {% firstof var1 var2 var3 "fallback value" %}
-    {% endfilter %}
-
-.. versionchanged:: 1.6
-
-    To improve safety, future versions of ``firstof`` will automatically escape
-    their output. You're encouraged to activate this behavior by loading
-    ``firstof`` from the ``future`` template library::
-
-        {% load firstof from future %}
-
-    When using the ``future`` version, you can disable auto-escaping with::
-
-        {% autoescape off %}
-            {% firstof var1 var2 var3 "<strong>fallback value</strong>" %}
-        {% endautoescape %}
+    {% autoescape off %}
+        {% firstof var1 var2 var3 "<strong>fallback value</strong>" %}
+    {% endautoescape %}
 
-    Or if only some variables should be escaped, you can use::
+Or if only some variables should be escaped, you can use::
 
-        {% firstof var1 var2|safe var3 "<strong>fallback value</strong>"|safe %}
+    {% firstof var1 var2|safe var3 "<strong>fallback value</strong>"|safe %}
 
 .. templatetag:: for
 

+ 4 - 4
tests/template_tests/tests.py

@@ -883,13 +883,13 @@ class TemplateTests(TestCase):
             'cycle17': ("{% cycle 'a' 'b' 'c' as abc silent %}{% cycle abc %}{% cycle abc %}{% cycle abc %}{% cycle abc %}", {}, ""),
             'cycle18': ("{% cycle 'a' 'b' 'c' as foo invalid_flag %}", {}, template.TemplateSyntaxError),
             'cycle19': ("{% cycle 'a' 'b' as silent %}{% cycle silent %}", {}, "ab"),
-            'cycle20': ("{% cycle one two as foo %} &amp; {% cycle foo %}", {'one': 'A & B', 'two': 'C & D'}, "A & B &amp; C & D"),
-            'cycle21': ("{% filter force_escape %}{% cycle one two as foo %} & {% cycle foo %}{% endfilter %}", {'one': 'A & B', 'two': 'C & D'}, "A &amp; B &amp; C &amp; D"),
+            'cycle20': ("{% cycle one two as foo %} &amp; {% cycle foo %}", {'one': 'A & B', 'two': 'C & D'}, "A &amp; B &amp; C &amp; D"),
+            'cycle21': ("{% filter force_escape %}{% cycle one two as foo %} & {% cycle foo %}{% endfilter %}", {'one': 'A & B', 'two': 'C & D'}, "A &amp;amp; B &amp; C &amp;amp; D"),
             'cycle22': ("{% for x in values %}{% cycle 'a' 'b' 'c' as abc silent %}{{ x }}{% endfor %}", {'values': [1, 2, 3, 4]}, "1234"),
             'cycle23': ("{% for x in values %}{% cycle 'a' 'b' 'c' as abc silent %}{{ abc }}{{ x }}{% endfor %}", {'values': [1, 2, 3, 4]}, "a1b2c3a4"),
             'included-cycle': ('{{ abc }}', {'abc': 'xxx'}, 'xxx'),
             'cycle24': ("{% for x in values %}{% cycle 'a' 'b' 'c' as abc silent %}{% include 'included-cycle' %}{% endfor %}", {'values': [1, 2, 3, 4]}, "abca"),
-            'cycle25': ('{% cycle a as abc %}', {'a': '<'}, '<'),
+            'cycle25': ('{% cycle a as abc %}', {'a': '<'}, '&lt;'),
 
             'cycle26': ('{% load cycle from future %}{% cycle a b as ab %}{% cycle ab %}', {'a': '<', 'b': '>'}, '&lt;&gt;'),
             'cycle27': ('{% load cycle from future %}{% autoescape off %}{% cycle a b as ab %}{% cycle ab %}{% endautoescape %}', {'a': '<', 'b': '>'}, '<>'),
@@ -929,7 +929,7 @@ class TemplateTests(TestCase):
             'firstof07': ('{% firstof a b "c" %}', {'a': 0}, 'c'),
             'firstof08': ('{% firstof a b "c and d" %}', {'a': 0, 'b': 0}, 'c and d'),
             'firstof09': ('{% firstof %}', {}, template.TemplateSyntaxError),
-            'firstof10': ('{% firstof a %}', {'a': '<'}, '<'),
+            'firstof10': ('{% firstof a %}', {'a': '<'}, '&lt;'),
 
             'firstof11': ('{% load firstof from future %}{% firstof a b %}', {'a': '<', 'b': '>'}, '&lt;'),
             'firstof12': ('{% load firstof from future %}{% firstof a b %}', {'a': '', 'b': '>'}, '&gt;'),