Login

Template tag to create a list from one or more variables and/or literals

Author:
davidchambers
Posted:
September 15, 2010
Language:
Python
Version:
1.2
Score:
2 (after 2 ratings)

This code is taken from a Stack Overflow answer by Will Hardy.

Usage: {% collect var1 var2 'foo' 'bar' 5 as some_list %}.

Sometimes one wishes to create a list on the fly within a template. Perhaps a collection needs to be passed to a template filter, but the collection cannot be created in the view since the values of one or more of its items are set in the template.

A contrived example:

{% with 5 as max %}{% with posts|length as len %}
    {% for post in posts %}
        {% if forloop.counter <= max %}
            {% include 'excerpt.dhtml' %}
        {% endif %}
    {% endfor %}
    {% collect len max as limits %}
    <p>Displaying {{ limits|minimum }} of {{ len }} post{{ posts|pluralize }}.</p>
{% endwith %}{% endwith %}

The final line will state how many posts are displayed: something like "5 of 24" or "2 of 2".

This particular problem can be solved in a number of other ways, some of which are more appropriate. Having a template tag that can create lists on the fly is potentially useful in quite a few situations, though.

I don't know whether this need is common enough to warrant being in the core. If something like this is to be included one day, it'd be much nicer to overload the with tag than to introduce a new tag. {% with var1 var2 var3 as some_list %} reads well.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@register.tag
def collect(parser, token):
    bits = list(token.split_contents())
    if len(bits) > 3 and bits[-2] == 'as':
        varname = bits[-1]
        items = bits[1:-2]
        return CollectNode(items, varname)
    else:
        raise template.TemplateSyntaxError('%r expected format is "item [item ...] as varname"' % bits[0])

class CollectNode(template.Node):
    def __init__(self, items, varname):
        self.items = map(template.Variable, items)
        self.varname = varname

    def render(self, context):
        context[self.varname] = [i.resolve(context) for i in self.items]
        return ''

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 2 weeks ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 10 months, 1 week ago
  5. Help text hyperlinks by sa2812 11 months ago

Comments

Tomek (on November 22, 2010):

It would be also nice to have possibility "collect" some value into tuple.

#

Please login first before commenting.