Prechádzať zdrojové kódy

Fixed #35668 -- Added mapping support to format_html_join.

nabil-rady 7 mesiacov pred
rodič
commit
231c0d8593

+ 7 - 1
django/utils/html.py

@@ -4,6 +4,7 @@ import html
 import json
 import re
 import warnings
+from collections.abc import Mapping
 from html.parser import HTMLParser
 from urllib.parse import parse_qsl, quote, unquote, urlencode, urlsplit, urlunsplit
 
@@ -155,7 +156,12 @@ def format_html_join(sep, format_string, args_generator):
     """
     return mark_safe(
         conditional_escape(sep).join(
-            format_html(format_string, *args) for args in args_generator
+            (
+                format_html(format_string, **args)
+                if isinstance(args, Mapping)
+                else format_html(format_string, *args)
+            )
+            for args in args_generator
         )
     )
 

+ 22 - 3
docs/ref/utils.txt

@@ -699,10 +699,29 @@ escaping HTML.
     joined using ``sep``. ``sep`` is also passed through
     :func:`conditional_escape`.
 
-    ``args_generator`` should be an iterator that returns the sequence of
-    ``args`` that will be passed to :func:`format_html`. For example::
+    ``args_generator`` should be an iterator that yields arguments to pass to
+    :func:`format_html`, either sequences of positional arguments or mappings of
+    keyword arguments.
 
-        format_html_join("\n", "<li>{} {}</li>", ((u.first_name, u.last_name) for u in users))
+    For example, tuples can be used for positional arguments::
+
+        format_html_join(
+            "\n",
+            "<li>{} {}</li>",
+            ((u.first_name, u.last_name) for u in users),
+        )
+
+    Or dictionaries can be used for keyword arguments::
+
+        format_html_join(
+            "\n",
+            '<li data-id="{id}">{id} {title}</li>',
+            ({"id": b.id, "title": b.title} for b in books),
+        )
+
+    .. versionchanged:: 5.2
+
+        Support for mappings in ``args_generator`` was added.
 
 .. function:: json_script(value, element_id=None, encoder=None)
 

+ 4 - 0
docs/releases/5.2.txt

@@ -267,6 +267,10 @@ Utilities
   values. This aligns with the :py:class:`str` addition behavior and allows
   ``__radd__`` to be used if available.
 
+* :func:`~django.utils.html.format_html_join` now supports taking an iterable
+  of mappings, passing their contents as keyword arguments to
+  :func:`~django.utils.html.format_html`.
+
 Validators
 ~~~~~~~~~~
 

+ 21 - 0
tests/utils_tests/test_html.py

@@ -10,6 +10,7 @@ from django.utils.html import (
     escape,
     escapejs,
     format_html,
+    format_html_join,
     html_safe,
     json_script,
     linebreaks,
@@ -75,6 +76,26 @@ class TestUtilsHtml(SimpleTestCase):
             name = "Adam"
             self.assertEqual(format_html(f"<i>{name}</i>"), "<i>Adam</i>")
 
+    def test_format_html_join_with_positional_arguments(self):
+        self.assertEqual(
+            format_html_join(
+                "\n",
+                "<li>{}) {}</li>",
+                [(1, "Emma"), (2, "Matilda")],
+            ),
+            "<li>1) Emma</li>\n<li>2) Matilda</li>",
+        )
+
+    def test_format_html_join_with_keyword_arguments(self):
+        self.assertEqual(
+            format_html_join(
+                "\n",
+                "<li>{id}) {text}</li>",
+                [{"id": 1, "text": "Emma"}, {"id": 2, "text": "Matilda"}],
+            ),
+            "<li>1) Emma</li>\n<li>2) Matilda</li>",
+        )
+
     def test_linebreaks(self):
         items = (
             ("para1\n\npara2\r\rpara3", "<p>para1</p>\n\n<p>para2</p>\n\n<p>para3</p>"),