开发者

Django - A counter template tag that works well even with nested for tag

I am trying to make a custom template tag that will increment a variable. That would be used like this:

{% for fruit in basket %}
    {if fruit.is_apple %}{% count apples %}{% endif %}
{% endfor %}
<p>There are {{ apples }} apples in your basket</p>

I came up with this:

#project/app/templatetags/counter.py

class CounterNode(template.Node):
    def __init__(self, varname):
        self.varname = varname

    def render(self, context):
        if self.varname in context:
            context[self.varname] += 1
        else:
            context[self.varname] = 1
        return ''


@register.tag
def counter(parser, token):
    try:
    开发者_C百科    tag_name, args = token.contents.split(None, 1)
    except ValueError:
        raise template.TemplateSyntaxError(
            "'counter' node requires a variable name.")
    return CounterNode(args)

This works fine until you try to use the counter tag within a for loop. The count variable increments inside the loop, but gets reset to 1 when the variable is called outside the loop.

This has to do with the render() method of the template.defaulttags.ForNode class, which calls context.pop() at the end, but I am not able to grasp why this is done and how it can be dealt with within my custom template tag.

So the question is: how could I get my counter tag to increment even through for loops?


Scrap the count tag and create either a model method that counts fruit or pass the count via the view method. Templates are not really intended for business logic, even if it as simple as counting.


I found django-templateaddons library that has {% counter %} tag that works on a template level independent of nested loops.


I have a technique that works well for limiting behavior within nested loops that doesn't require any custom tags. The only limitation is that you must know in advance the upper limit you're trying to set. In our case, we knew we wanted to only display the first six image galleries out of an arbitrary number of publishers, and galleries per publisher. It's strictly a presentation layer limit, so we didn't want to special-case the view. The major caveat is that you must have n+1 values in the cycle tag to insure nothing repeats. Yes, I know I'm referring to 'mycycle' before it is declared, but since you can't really declare a variable inside the Django template language, I think I can be forgiven; it works great.

{% for pubs in sortedpubs %}
    {% for gallery in pubs.publisher.galleries.all %}
        {# Code to count inside nested loops... #}
        {# Uses "cycle" from the next line to count up to 6, then stop rendering #}
        {% if mycycle < 6 %} 
            <!-- {% cycle 1 2 3 4 5 6 7 as mycycle %} -->
            {# ...Render Stuff here... #}
        {% endif %}
    {% endfor %} 
{% endfor %}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜