]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
add default parameter to groupby 1360/head
authorlisongmin <lisongmin@protonmail.com>
Tue, 23 Feb 2021 06:34:36 +0000 (14:34 +0800)
committerDavid Lord <davidism@gmail.com>
Mon, 5 Apr 2021 21:42:34 +0000 (14:42 -0700)
CHANGES.rst
src/jinja2/asyncfilters.py
src/jinja2/filters.py
tests/test_filters.py

index dd3739fb5dedf767a054e980043dc157a92eb808..c94894ac63c73b87764d7d308f47a4dd3a78d50f 100644 (file)
@@ -58,6 +58,8 @@ Unreleased
 -   ``NativeEnvironment`` supports async mode. :issue:`1362`
 -   Template rendering only treats ``\n``, ``\r\n`` and ``\r`` as line
     breaks. Other characters are left unchanged. :issue:`769, 952, 1313`
+-   ``|groupby`` filter takes an optional ``default`` argument.
+    :issue:`1359`
 
 
 Version 2.11.3
index 11b031a355b4a9e0013e0f172c27aeefb4b1ede4..dfd8cba0526ddd850df6583442e8f060d6ac8a81 100644 (file)
@@ -107,8 +107,9 @@ async def do_groupby(
     environment: "Environment",
     value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
     attribute: t.Union[str, int],
+    default: t.Optional[t.Any] = None,
 ) -> "t.List[t.Tuple[t.Any, t.List[V]]]":
-    expr = filters.make_attrgetter(environment, attribute)
+    expr = filters.make_attrgetter(environment, attribute, default=default)
     return [
         filters._GroupTuple(key, await auto_to_seq(values))
         for key, values in groupby(sorted(await auto_to_seq(value), key=expr), expr)
index 33353e5c4222762b6ec32c1971e5ba0c1f86395c..c925f837ac588626d8dbcf5cfcecbf089fdd1784 100644 (file)
@@ -1116,7 +1116,10 @@ class _GroupTuple(t.NamedTuple):
 
 @environmentfilter
 def do_groupby(
-    environment: "Environment", value: "t.Iterable[V]", attribute: t.Union[str, int]
+    environment: "Environment",
+    value: "t.Iterable[V]",
+    attribute: t.Union[str, int],
+    default: t.Optional[t.Any] = None,
 ) -> "t.List[t.Tuple[t.Any, t.List[V]]]":
     """Group a sequence of objects by an attribute using Python's
     :func:`itertools.groupby`. The attribute can use dot notation for
@@ -1148,10 +1151,22 @@ def do_groupby(
           <li>{{ group.grouper }}: {{ group.list|join(", ") }}
         {% endfor %}</ul>
 
+    You can specify a ``default`` value to use if an object in the list
+    does not have the given attribute.
+
+    .. sourcecode:: jinja
+
+        <ul>{% for city, items in users|groupby("city", default="NY") %}
+          <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
+        {% endfor %}</ul>
+
+    .. versionchanged:: 3.0
+        Added the ``default`` parameter.
+
     .. versionchanged:: 2.6
         The attribute supports dot notation for nested access.
     """
-    expr = make_attrgetter(environment, attribute)
+    expr = make_attrgetter(environment, attribute, default=default)
     return [
         _GroupTuple(key, list(values))
         for key, values in groupby(sorted(value, key=expr), expr)
index 2c119c37efc81b9afb92f7d878917012ff975cf2..0843246bb2aab5773906af72d3773f30c9df8db7 100644 (file)
@@ -593,6 +593,21 @@ class TestFilter:
             "",
         ]
 
+    def test_groupby_default(self, env):
+        tmpl = env.from_string(
+            "{% for city, items in users|groupby('city', default='NY') %}"
+            "{{ city }}: {{ items|map(attribute='name')|join(', ') }}\n"
+            "{% endfor %}"
+        )
+        out = tmpl.render(
+            users=[
+                {"name": "emma", "city": "NY"},
+                {"name": "smith", "city": "WA"},
+                {"name": "john"},
+            ]
+        )
+        assert out == "NY: emma, john\nWA: smith\n"
+
     def test_filtertag(self, env):
         tmpl = env.from_string(
             "{% filter upper|replace('FOO', 'foo') %}foobar{% endfilter %}"