Kaydet (Commit) 61b45dff authored tarafından Baptiste Mispelon's avatar Baptiste Mispelon Kaydeden (comit) Tim Graham

Fixed #27126 -- Made {% regroup %} return a namedtuple to ease unpacking.

üst 7968bb7f
...@@ -4,6 +4,7 @@ from __future__ import unicode_literals ...@@ -4,6 +4,7 @@ from __future__ import unicode_literals
import re import re
import sys import sys
import warnings import warnings
from collections import namedtuple
from datetime import datetime from datetime import datetime
from itertools import cycle as itertools_cycle, groupby from itertools import cycle as itertools_cycle, groupby
...@@ -335,6 +336,9 @@ class LoremNode(Node): ...@@ -335,6 +336,9 @@ class LoremNode(Node):
return '\n\n'.join(paras) return '\n\n'.join(paras)
GroupedResult = namedtuple('GroupedResult', ['grouper', 'list'])
class RegroupNode(Node): class RegroupNode(Node):
def __init__(self, target, expression, var_name): def __init__(self, target, expression, var_name):
self.target, self.expression = target, expression self.target, self.expression = target, expression
...@@ -355,7 +359,7 @@ class RegroupNode(Node): ...@@ -355,7 +359,7 @@ class RegroupNode(Node):
# List of dictionaries in the format: # List of dictionaries in the format:
# {'grouper': 'key', 'list': [list of contents]}. # {'grouper': 'key', 'list': [list of contents]}.
context[self.var_name] = [ context[self.var_name] = [
{'grouper': key, 'list': list(val)} GroupedResult(grouper=key, list=list(val))
for key, val in for key, val in
groupby(obj_list, lambda obj: self.resolve_expression(obj, context)) groupby(obj_list, lambda obj: self.resolve_expression(obj, context))
] ]
......
...@@ -896,13 +896,36 @@ resulting list. Here, we're regrouping the ``cities`` list by the ``country`` ...@@ -896,13 +896,36 @@ resulting list. Here, we're regrouping the ``cities`` list by the ``country``
attribute and calling the result ``country_list``. attribute and calling the result ``country_list``.
``{% regroup %}`` produces a list (in this case, ``country_list``) of ``{% regroup %}`` produces a list (in this case, ``country_list``) of
**group objects**. Each group object has two attributes: **group objects**. Group objects are instances of
:py:func:`~collections.namedtuple` with two fields:
* ``grouper`` -- the item that was grouped by (e.g., the string "India" or * ``grouper`` -- the item that was grouped by (e.g., the string "India" or
"Japan"). "Japan").
* ``list`` -- a list of all items in this group (e.g., a list of all cities * ``list`` -- a list of all items in this group (e.g., a list of all cities
with country='India'). with country='India').
.. versionchanged:: 1.11
The group object was changed from a dictionary to a
:py:func:`~collections.namedtuple`.
Because ``{% regroup %}`` produces :py:func:`~collections.namedtuple` objects,
you can also write the previous example as::
{% regroup cities by country as country_list %}
<ul>
{% for country, local_cities in country_list %}
<li>{{ country }}
<ul>
{% for city in local_cities %}
<li>{{ city.name }}: {{ city.population }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Note that ``{% regroup %}`` does not order its input! Our example relies on Note that ``{% regroup %}`` does not order its input! Our example relies on
the fact that the ``cities`` list was ordered by ``country`` in the first place. the fact that the ``cities`` list was ordered by ``country`` in the first place.
If the ``cities`` list did *not* order its members by ``country``, the If the ``cities`` list did *not* order its members by ``country``, the
......
...@@ -300,6 +300,10 @@ Templates ...@@ -300,6 +300,10 @@ Templates
supports context processors by setting the ``'context_processors'`` option in supports context processors by setting the ``'context_processors'`` option in
:setting:`OPTIONS <TEMPLATES-OPTIONS>`. :setting:`OPTIONS <TEMPLATES-OPTIONS>`.
* The :ttag:`regroup` tag now returns ``namedtuple``\s instead of dictionaries
so you can unpack the group object directly in a loop, e.g.
``{% for grouper, list in regrouped %}``.
Tests Tests
~~~~~ ~~~~~
......
...@@ -100,3 +100,22 @@ class RegroupTagTests(SimpleTestCase): ...@@ -100,3 +100,22 @@ class RegroupTagTests(SimpleTestCase):
def test_regroup08(self): def test_regroup08(self):
with self.assertRaises(TemplateSyntaxError): with self.assertRaises(TemplateSyntaxError):
self.engine.get_template('regroup08') self.engine.get_template('regroup08')
@setup({'regroup_unpack': '{% regroup data by bar as grouped %}'
'{% for grouper, group in grouped %}'
'{{ grouper }}:'
'{% for item in group %}'
'{{ item.foo }}'
'{% endfor %},'
'{% endfor %}'})
def test_regroup_unpack(self):
output = self.engine.render_to_string('regroup_unpack', {
'data': [
{'foo': 'c', 'bar': 1},
{'foo': 'd', 'bar': 1},
{'foo': 'a', 'bar': 2},
{'foo': 'b', 'bar': 2},
{'foo': 'x', 'bar': 3},
],
})
self.assertEqual(output, '1:cd,2:ab,3:x,')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment