B Robster
B Robster

Reputation: 42043

Splitting a list with django template tags

I have a single list my_list in my context, and I'd like to render it as two "columns", with the first (n+1)/2 items in the first column and the last n/2 items in the second column. Is there a straight-forward way to do this with django template tags/filters or do I need to pre-split the list into two in my view?

e.g.,

<div class="split-50-left">
  <ul> 
    {% for item in [first half of my_list] %}
      <li>{{item}}</li>
    {% endfor %}
  </ul>
</div>
<div class="split-50-right">
  <ul> 
    {% for item in [second half of my_list] %}
      <li>{{item}}</li>
    {% endfor %}
  </ul>
</div>

Upvotes: 9

Views: 12218

Answers (4)

putty
putty

Reputation: 764

Does it make sense at all to use css? I believe it would work everywhere except IE9.

<ul class="two-columns">
{% for item in object_list %}
  <li>{{ item }}</li>
{% endfor %}
</ul>

And then the css:

ul.two-columns {
    -moz-column-count: 2;
    -webkit-column-count: 2;
    column-count: 2;
}

Upvotes: 1

Aidan Fitzpatrick
Aidan Fitzpatrick

Reputation: 2035

If you could interpolate the two halves -- or if splitting down the middle isn't critical -- you could render alternate values separately. This'll be cheaper:

<ul><!-- Half of the list -->
    {% for i in values %}
        {% cycle 'odd' 'even' as state silent %}
        {% if state == 'odd' %}
            <li>{{ i }}</li>
        {% endif %}
    {% endfor %}
</ul>

<ul><!-- The other half -->
    {% for i in values %}
        {% cycle 'odd' 'even' as state silent %}
        {% if state == 'even' %}
            <li>{{ i }}</li>
        {% endif %}
    {% endfor %}
</ul>

Upvotes: 1

Grant Anderson
Grant Anderson

Reputation: 362

A (slightly hacky) way to do this entirely in the template is to use widthratio template tag to work out the centre of the list and the with template tag to create temporary variables.

{% widthratio form.visible_fields|length 2 1 as visible_fields_centre %}
<div class="rows_form">
    {% with ":"|add:visible_fields_centre as first_slice %}
        {% for field in form.visible_fields|slice:first_slice %}
            {{ field }}
        {% endfor %}
    {% endwith %}
</div>
<div class="rows_form">
    {% with visible_fields_centre|add:":" as second_slice %}
        {% for field in form.visible_fields|slice:second_slice %}
            {{ field }}
        {% endfor %}
    {% endwith %}
</div>

Upvotes: 2

JcKelley
JcKelley

Reputation: 1984

The more 'Django' way would be to do it in the view, as you are supposed to keep as much logic out of your template as possible. That being said, there is a ways you can do it through the template.

You can use the slice template tag if you already know how many are in the list. Let's assume you don't though.

The other method would be to just loop over it twice, and only display half you want. You would be going over the entire list though each time, so it might be expensive. It uses the forloop counter.

{% for item in items %}
#half list is calculated in your view. It is the items query /2
   {% if forloop.counter < half_list %}
       {% item.name %}
   {% endif %}
{% endfor %}

{% for item in items %}
#half list is calculated in your view. It is the items query /2
    {% if forloop.counter >= half_list %}
        {% item.name %}
    {% endif %}
{% endfor %}

Upvotes: 13

Related Questions