21

I have some loop on the page and need list item depending from loop number.

When I call:

{{ mylist.1 }}
{{ mylist.2 }}
{{ mylist.3 }}

all works fine but what I really need is something like:

{% for x in somenumber|MyCustomRangeTag %}
    {{ mylist.x }}
{% endfor %}

MyCustomRangeTag gives me Python range() it works and I already have x as number. So x is 1, 2, 3 etc. depending from loop number. Is this possible and how?

juliomalegria
  • 24,229
  • 14
  • 73
  • 89
Goran
  • 6,644
  • 11
  • 34
  • 54
  • can you just pass the values you need in the view? if you know the range before hand why not just pass the exact values you are trying to display? – dm03514 Jan 20 '12 at 22:06
  • No, I can't in this case. It's hard coded custom shopping cart page and all this is a part of the some nested forms. – Goran Jan 20 '12 at 22:17

5 Answers5

30

This is not possible directly because Django thinks that "x" is the key to lookup in mylist - instead of the value of x. So, when x = 5, Django tries to look up mylist["x"] instead of mylist[5].

Use the following filter as workaround:

@register.filter
def lookup(d, key):
    return d[key]

and use it like

{{ mylist|lookup:x }}
AndiDog
  • 68,631
  • 21
  • 159
  • 205
  • 2
    What if the output of `{{ mylist|lookup:x }}` is an object and I further need to access something? Something like `mylist.1.first_name` – zengr Aug 12 '14 at 18:31
  • 3
    @zengr Try `{% with lookup_result=mylist|lookup:x %}{{lookup_result.first_name}}{% endwith %}`. – valid Jul 20 '15 at 10:37
5

The slice tag in Django templates may use python's slicing code, but the syntax is unmistakably different. For instance, if you wanted to get an element of a sequence with a variable, in python you'd write something similar to the following:

>>>mylist = ["0th Element", "1th Element"]
>>>zero, one = 0, 1
>>>mylist[zero]
"0th Element"
>>>mylist[one]
"1th Element"

Using this syntax with the Django slice template tag will return a sliced list in every case, of dubious utility for getting an item of known index:

{% with "0" as zero %}
{% with "1" as one %}
{% with "2" as two %}

{{mylist|slice:zero}} {{mylist|slice:one}} {{mylist|slice:two}}

{% endwith %}
{% endwith %}
{% endwith %}

Renders to the html:

[] ["0th Element"] ["0th Element", "1th Element"]

Note the differences: you are getting the result of mylist[:x] instead of mylist[x].

Django provides enough tools to work around this. The first trick is to use explicit slices like 0:1 for your indices, and then |join:"" the resultant list into a single element. Like so:

{% with "0:1" as zero %}
{{mylist|slice:zero|join:""}}
{% endwith %}

Yields:

0th Element

This comes in particularly handy if you need to access a parent loop's index when dealing with an iterable inside a child loop:

{% for parent in parent_loop %}
    {% cycle "0:1" "1:2" "2:3" as parent_loop_index silent %}
    {% for child in child_loop %}
        {{child|slice:parent_loop_index|join:""}}
    {% endfor %}
{% endfor %}

Completed with nothing but stock parts, although I don't think Django has implemented achievements yet.

TimClifford
  • 255
  • 4
  • 10
5

I notice that @e-satis mentioned it, but I think the built-in slice template tag deserves some love.

{{ item | slice:"2" }} #gets the third element of the list
Matt Luongo
  • 14,371
  • 6
  • 53
  • 64
  • this may have worked previously but gave some funky results when I gave it a shot with django 1.5 – Alvin Jun 24 '14 at 20:25
  • This didn't work for me, but `{{ some_list|slice:":2" }}` did the trick --https://docs.djangoproject.com/en/1.7/ref/templates/builtins/#slice – Hayden Apr 21 '15 at 16:44
  • @Hayden I believe that only gets the first two elements of the list? I updated the code to fix the filter syntax. – Matt Luongo Aug 02 '15 at 17:40
  • This gets the third element of the list, but still doesn't work to get an element from a list when the index you want to use is stored in a var – Mouscellaneous Aug 19 '15 at 16:33
  • 2
    `{% with "2" as var %} {{ mylist | slice: var }} {% endwith %}` – Matt Luongo Aug 20 '15 at 17:56
4

Are you sure you can't just do:

{% for item in mylist %}
    {{ item }}
{% endfor %}

With the slice filter, you can even do some customisation.

Bite code
  • 578,959
  • 113
  • 301
  • 329
  • I think you mean to have `{{ item }}` on the second line. It's also worth noting here that you could use `{{ forloop.counter }}` within the loop if you need an index for some reason. – aganders3 Jan 20 '12 at 22:23
  • Haha, no worries. Thanks for the tip, though. I actually wasn't intimidated by your rep, I just forgot we are able to edit answers. This will inspire me when I feel shy in the future, though. – aganders3 Jan 20 '12 at 22:59
0

Following worked for me

{% for 1,2,3 in mylist %}
# do stuff

Just don't use brackets around 1,2,3

Ayush Gaba
  • 41
  • 1