JackLeo
JackLeo

Reputation: 4740

Django template for loop. Member before

I want to create such loop:

{% for object in objects %}
    {% if object.before != object %}
         {{ object }} this is different
    {% else %}
        {{ object }} this is the same
{% endfor %}

Based on https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#for I can't. Is there really no simple way to do this? Or I just need to use counter and check for objects[counter-1]?

P.S. .before is theoretical and objects is simple query list. I want to take and do something with the loop member that encountered before current loop member.

Upvotes: 1

Views: 2667

Answers (4)

Dave
Dave

Reputation: 2526

The built-in template tags and filters don't make it easy (as of Django 1.4), but it is possible by using the with tag to cache variables and the add, slugify, and slice filters to generate a new list with only one member.

The following example creates a new list whose sole member is the previous member of the forloop:

{% for item in list %}
    {% if not forloop.first %}
        {% with forloop.counter0|add:"-1" as previous %}
        {% with previous|slugify|add:":"|add:previous as subset %}
        {% with list|slice:subset as sublist %}

        <p>Current item: {{ item }}</p>
        <p>Previous item: {{ sublist.0 }}</p>

        {% endwith %}
        {% endwith %}
        {% endwith %}
    {% endif %}
{% endfor %}

This isn't an elegant solution, but the django template system has two faults that make this hack unavoidable for those who don't what to write custom tags:

  1. Django template syntax does not allow nested curly parenthesis. Otherwise, we could do this:

        {{ list.{{ forloop.counter|add:-1  }} }}
    
  2. The lookup operator does not accept values stored using with (and perhaps for good reason)

        {% with forloop.counter|add:-1 as index %}
            {{ list.index }}
        {% endwith %}
    

Upvotes: 0

ArturM
ArturM

Reputation: 703

Check ifchanged template tag

Upvotes: 7

Daniel Roseman
Daniel Roseman

Reputation: 599846

There is a "simple way" to do this: write a custom template tag. They're really not hard. This would probably do the trick (untested):

@register.simple_tag
def compare_objects(object_list):
    comparisons = []
    for i in range(1, len(object_list)):
        if object_list[i] > object_list[i-1]:
            comparisons.append('bigger')
        else:
            comparisons.append('smaller')
    return comparisons

Upvotes: 0

Marcin
Marcin

Reputation: 49856

This code should work just fine as a django template, as long as object has a property or no-argument method called before, and objects is iterable (and '<' is defined).

{% for object in objects %}
    {% if object.before < object %}
        this is bigger
    {% else %}
        this is smaller
{% endfor %}

Upvotes: -2

Related Questions