瀏覽代碼

Fixed #34577 -- Added escapeseq template filter.

Arthur Moreira 1 年之前
父節點
當前提交
061a8a1bd8

+ 1 - 0
AUTHORS

@@ -108,6 +108,7 @@ answer newbie questions, and generally made Django that much better:
     Arthur <avandorp@gmail.com>
     Arthur Jovart <arthur@jovart.com>
     Arthur Koziel <http://arthurkoziel.com>
+    Arthur Moreira <moreirarthur96@gmail.com>
     Arthur Rio <arthur.rio44@gmail.com>
     Arvis Bickovskis <viestards.lists@gmail.com>
     Arya Khaligh <bartararya@gmail.com>

+ 10 - 0
django/template/defaultfilters.py

@@ -444,6 +444,16 @@ def escape_filter(value):
     return conditional_escape(value)
 
 
+@register.filter(is_safe=True)
+def escapeseq(value):
+    """
+    An "escape" filter for sequences. Mark each element in the sequence,
+    individually, as a string that should be auto-escaped. Return a list with
+    the results.
+    """
+    return [conditional_escape(obj) for obj in value]
+
+
 @register.filter(is_safe=True)
 @stringfilter
 def force_escape(value):

+ 19 - 0
docs/ref/templates/builtins.txt

@@ -1831,6 +1831,8 @@ For example, you can apply ``escape`` to fields when :ttag:`autoescape` is off:
         {{ title|escape }}
     {% endautoescape %}
 
+To escape each element of a sequence, use the :tfilter:`escapeseq` filter.
+
 .. templatefilter:: escapejs
 
 ``escapejs``
@@ -1849,6 +1851,23 @@ For example:
 If ``value`` is ``"testing\r\njavascript 'string\" <b>escaping</b>"``,
 the output will be ``"testing\\u000D\\u000Ajavascript \\u0027string\\u0022 \\u003Cb\\u003Eescaping\\u003C/b\\u003E"``.
 
+.. templatefilter:: escapeseq
+
+``escapeseq``
+-------------
+
+.. versionadded:: 5.0
+
+Applies the :tfilter:`escape` filter to each element of a sequence. Useful in
+conjunction with other filters that operate on sequences, such as
+:tfilter:`join`. For example:
+
+.. code-block:: html+django
+
+    {% autoescape off %}
+        {{ my_list|escapeseq|join:", " }}
+    {% endautoescape %}
+
 .. templatefilter:: filesizeformat
 
 ``filesizeformat``

+ 2 - 1
docs/releases/5.0.txt

@@ -345,7 +345,8 @@ Signals
 Templates
 ~~~~~~~~~
 
-* ...
+* The new :tfilter:`escapeseq` template filter applies :tfilter:`escape` to
+  each element of a sequence.
 
 Tests
 ~~~~~

+ 59 - 0
tests/template_tests/filter_tests/test_escapeseq.py

@@ -0,0 +1,59 @@
+from django.test import SimpleTestCase
+from django.utils.safestring import mark_safe
+
+from ..utils import setup
+
+
+class EscapeseqTests(SimpleTestCase):
+    """
+    The "escapeseq" filter works the same whether autoescape is on or off,
+    and has no effect on strings already marked as safe.
+    """
+
+    @setup(
+        {
+            "escapeseq_basic": (
+                '{{ a|escapeseq|join:", " }} -- {{ b|escapeseq|join:", " }}'
+            ),
+        }
+    )
+    def test_basic(self):
+        output = self.engine.render_to_string(
+            "escapeseq_basic",
+            {"a": ["x&y", "<p>"], "b": [mark_safe("x&y"), mark_safe("<p>")]},
+        )
+        self.assertEqual(output, "x&amp;y, &lt;p&gt; -- x&y, <p>")
+
+    @setup(
+        {
+            "escapeseq_autoescape_off": (
+                '{% autoescape off %}{{ a|escapeseq|join:", " }}'
+                " -- "
+                '{{ b|escapeseq|join:", "}}{% endautoescape %}'
+            )
+        }
+    )
+    def test_autoescape_off(self):
+        output = self.engine.render_to_string(
+            "escapeseq_autoescape_off",
+            {"a": ["x&y", "<p>"], "b": [mark_safe("x&y"), mark_safe("<p>")]},
+        )
+        self.assertEqual(output, "x&amp;y, &lt;p&gt; -- x&y, <p>")
+
+    @setup({"escapeseq_join": '{{ a|escapeseq|join:"<br/>" }}'})
+    def test_chain_join(self):
+        output = self.engine.render_to_string("escapeseq_join", {"a": ["x&y", "<p>"]})
+        self.assertEqual(output, "x&amp;y<br/>&lt;p&gt;")
+
+    @setup(
+        {
+            "escapeseq_join_autoescape_off": (
+                '{% autoescape off %}{{ a|escapeseq|join:"<br/>" }}{% endautoescape %}'
+            ),
+        }
+    )
+    def test_chain_join_autoescape_off(self):
+        output = self.engine.render_to_string(
+            "escapeseq_join_autoescape_off", {"a": ["x&y", "<p>"]}
+        )
+        self.assertEqual(output, "x&amp;y<br/>&lt;p&gt;")