Index: django/template/defaultfilters.py
===================================================================
--- django/template/defaultfilters.py (revision 10031)
+++ django/template/defaultfilters.py (working copy)
@@ -633,6 +633,69 @@
unordered_list.is_safe = True
unordered_list.needs_autoescape = True
+def columns(thelist, n):
+ """
+ Breaks a list into ``n`` number of columns, filling up each column to the
+ maximum equal length possible. This filter will always return ``n``
+ columns, even if some are empty.
+
+ Usage::
+
+ {% for item_column in item_list|columns:3 %}
+
+
+ {% for item in item_column %}
+ - {{ item }}
+ {% endfor %}
+
+
+ {% endfor %}
+
+ """
+ try:
+ n = int(n)
+ thelist = list(thelist)
+ except (ValueError, TypeError):
+ return [thelist]
+
+ list_len = len(thelist)
+ split = list_len // n
+
+ if list_len % n != 0:
+ split += 1
+
+ return [thelist[split*i:split*(i+1)] for i in range(n)]
+
+def rows(thelist, n):
+ """
+ Breaks a list into rows with a maximum number of ``n`` elements in each.
+
+ Usage::
+
+ {% for item_row in item_list|rows:4 %}
+
+
+ {% for item in item_row %}
+ - {{ item }}
+ {% endfor %}
+
+
+ {% endfor %}
+
+ """
+ try:
+ n = int(n)
+ thelist = list(thelist)
+ except (ValueError, TypeError):
+ return [thelist]
+
+ newlists = [list() for i in range(int(ceil(len(thelist) / float(n))))]
+
+ for i, val in enumerate(thelist):
+ newlists[i/n].append(val)
+
+ return newlists
+
###################
# INTEGERS #
###################
@@ -896,6 +959,8 @@
register.filter(truncatewords)
register.filter(truncatewords_html)
register.filter(unordered_list)
+register.filter(columns)
+register.filter(rows)
register.filter(upper)
register.filter(urlencode)
register.filter(urlize)