views:

345

answers:

3

I am outputting a series of Django objects in a template:

{% for obj in list %}
    ...
{% endfor %}

But I'd like to only output the first five of these, then put the remainder in the seperate <DIV>. The idea being, that I can hide the second half until required.

I envisage something like this, but need to restrict the elements iterated:

{% for obj in list %}
    ...
{% endfor %}

<a href="" onclick="unhide()">Show hidden</a>
<div id="hidden">
    {% for obj in list %}
        ...
    {% endfor %}
</div>

Is it possible to do this within the template alone? It's presentation logic, so I'd rather not pollute the view.

+2  A: 

Sure, for example you can do the loop twice and within it use forloop.counter in suitable if constructs -- the first time to only do stuff when it's <= 5, the second time only when it's > 5 (remember it's 1-based -- if you want a 0-based one, use forloop.counter0 instead).

Alex Martelli
+13  A: 

You could use slice:

{% for obj in list|slice:":5" %}
    ...
{% endfor %}

<a href="" onclick="unhide()">Show hidden</a>
<div id="hidden">
    {% for obj in list|slice:"5:" %}
        ...
    {% endfor %}
</div>
Paolo Bergantino
+7  A: 

Struggling with template limitations can often be a sign that life might be simpler if you did more work in your view:

context = {
  'visible_list': mylist[:5],
  'hidden_list': mylist[5:]
}

I'm not saying this is neccesarily any better than the slice filter solution above but it's often worth considering passing your templates a context object with everything set up nicely. It allows you to adapt more easily should the logic get even more complex later on.

Presentation logic sits quite nicely in a view. I don't particularly see it as 'pollution'.

andybak
This approach has the additional benefit of making it very easy to add a conditional in the template to avoid showing "Show hidden" if there aren't any hidden.
Dave W. Smith