groupby now supports attributes of attributes. This fixes #10
authorArmin Ronacher <armin.ronacher@active-4.com>
Mon, 20 Dec 2010 23:44:34 +0000 (00:44 +0100)
committerArmin Ronacher <armin.ronacher@active-4.com>
Mon, 20 Dec 2010 23:44:34 +0000 (00:44 +0100)
CHANGES
jinja2/compiler.py
jinja2/filters.py
jinja2/testsuite/filters.py

diff --git a/CHANGES b/CHANGES
index b171ac29be1e4d1792ab7af7345cdcbb0cbac484..87f705cb22876f7b1c3c6336856654be18de593b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -13,6 +13,8 @@ Version 2.6
   allows application developers to disable builtin operators for better
   security.  (For instance limit the mathematical operators to actual
   integers instead of longs)
+- groupby filter now supports dotted notation for grouping by attributes
+  of attributes.
 
 Version 2.5.5
 -------------
index 657a8bcf045786ea7032776562394ca851c721e0..a4b5a2f91eb7d3c27d4e98af3aa8c18393a64a70 100644 (file)
@@ -13,7 +13,7 @@ from itertools import chain
 from copy import deepcopy
 from jinja2 import nodes
 from jinja2.nodes import EvalContext
-from jinja2.visitor import NodeVisitor, NodeTransformer
+from jinja2.visitor import NodeVisitor
 from jinja2.exceptions import TemplateAssertionError
 from jinja2.utils import Markup, concat, escape, is_python_keyword, next
 
index d1848e434d32405ed8e597de19288af80a4b3f85..3a81f70ba045b5f0bead3e6036c6a899a8c75ef8 100644 (file)
@@ -595,8 +595,18 @@ def do_groupby(environment, value, attribute):
     As you can see the item we're grouping by is stored in the `grouper`
     attribute and the `list` contains all the objects that have this grouper
     in common.
+
+    .. versionchanged:: 2.6
+       It's now possible to use dotted notation to group by the child
+       attribute of another attribute.
     """
-    expr = lambda x: environment.getitem(x, attribute)
+    if '.' in attribute:
+        def expr(item):
+            for part in attribute.split('.'):
+                item = environment.getitem(item, part)
+            return item
+    else:
+        expr = lambda x: environment.getitem(x, attribute)
     return sorted(map(_GroupTuple, groupby(sorted(value, key=expr), expr)))
 
 
index b59c9e38de0c3b2756f76ede6db5173e9f9cc489..80a6f805ffc5396d931c041171e36949594e5e88 100644 (file)
@@ -252,6 +252,32 @@ class FilterTestCase(JinjaTestCase):
             ""
         ]
 
+    def test_groupby_multidot(self):
+        class Date(object):
+            def __init__(self, day, month, year):
+                self.day = day
+                self.month = month
+                self.year = year
+        class Article(object):
+            def __init__(self, title, *date):
+                self.date = Date(*date)
+                self.title = title
+        articles = [
+            Article('aha', 1, 1, 1970),
+            Article('interesting', 2, 1, 1970),
+            Article('really?', 3, 1, 1970),
+            Article('totally not', 1, 1, 1971)
+        ]
+        tmpl = env.from_string('''
+        {%- for year, list in articles|groupby('date.year') -%}
+            {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
+        {%- endfor %}''')
+        assert tmpl.render(articles=articles).split('|') == [
+            '1970[aha][interesting][really?]',
+            '1971[totally not]',
+            ''
+        ]
+
     def test_filtertag(self):
         tmpl = env.from_string("{% filter upper|replace('FOO', 'foo') %}"
                                "foobar{% endfilter %}")