How to display the last result in a FOR list - django

I have the following list:
{% for artist_form in artist_formset %}
...
{% endfor %}
How can I display just the last result in the list?
Thanks

From the docs: https://docs.djangoproject.com/en/1.6/ref/templates/builtins/#last
Use 'last' tag to get the last item of a list.

In views.py:
last_artist = artist_formset[-1]
In your-template.html:
{{ last_artist }}

Related

Accessing nested list by variable in Django templates [duplicate]

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?
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 }}
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.
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
Are you sure you can't just do:
{% for item in mylist %}
{{ item }}
{% endfor %}
With the slice filter, you can even do some customisation.
Following worked for me
{% for 1,2,3 in mylist %}
# do stuff
Just don't use brackets around 1,2,3

Django template variables as key for a list

I'm coming from this question Use variable as dictionary key in Django template
i've this context created in my view:
{'cats': {'LIST1': ['a','b','c'], 'LIST2': ['aa','bb','cc','dd'], 'LIST3': ['f','g']}}
what i want to do is to print the list title and then all the items, something like
LIST1:
- a
- b
- c
for all the lists, so i did this in my template
{% for l_name, l in cats %}
{{ l_name }}
{%for lv in l %}
{{ lv }}
{% endfor %}
{% endfor %}
and this prints only the list names, without printing out the list. where's the mistake?
thanks
If you want to iterate over keys and values, you can use:
{% for name, lst in cats.iteritems %}
....
{% endfor %}
This just calls the iteritems method of a dictionary, which returns an iterator over a list of 2-tuples.
Django's {% for %} tag documentation has some nice example of this too.
Just for the record, the problem is how the data are created. so instead of
{'cats': {'LIST1': ['a','b','c'], 'LIST2': ['aa','bb','cc','dd'], 'LIST3': ['f','g']}}
i need a list of touple so:
{'cats': [('LIST1', ['a','b','c']), ('LIST2', ['aa','bb','cc','dd']), ('LIST3', ['f','g'])]}

Skip the first element in list

Is it possible with django template tags to skip the first element in a list when doing the for loop? For example I want to begin from element 1 instead from 0.
builtin slice filter
{{ qs|slice:"1:" }}
You can e.g. do:
{% if not forloop.first %}
...
{% endif %}

Get list item dynamically in django templates

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?
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 }}
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.
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
Are you sure you can't just do:
{% for item in mylist %}
{{ item }}
{% endfor %}
With the slice filter, you can even do some customisation.
Following worked for me
{% for 1,2,3 in mylist %}
# do stuff
Just don't use brackets around 1,2,3

"Last" tag not working

I have a queryset of "promotion" events which are rendered in a template. Each of these promotions also have 1 or more appointments. What I want to do is display the dates of the first and last appointments.
So far, using the "first" tag works. However, using the "last" tag causes:
TemplateSyntaxError Exception Value:
Caught an exception while rendering:
Negative indexing is not supported.
Here's the template script
{% for promotion in promotions%}
{% with promotion.appointment_set.all as appointments %}
{% with appointments|first as first_ap %}
{{ first_ap.date|date }}
{% endwith %}
{% with appointments|last as last_ap %}
{{ last_ap.date|date }}
{% endwith %}
{% endwith %}
{% endfor %}
What am I doing wrong here?
Converting the queryset into a list before giving it to the template also gets you where you want to go:
return render_to_response(template, {
appointments: list(Appointments.objects.all())
})
Since I'm using the whole list I do something like this (which might be open to improvement):
{% for ap in appointments %}
{% ifequal ap appointments|last %}
ap.date
{% endifequal %}
{% endfor %}
The object attributes still work. eg: ap.user.full_name
The last tag works by slicing a list to get the last item, using the negative index format: collection[-1]. But as the error message points out, negative indexing is not supported on querysets.
Probably the easiest way of solving this is to create a new method on your Promotion model to return the last appointment:
class Promotion(models.Model):
... fields, etc ...
def get_last_appointment(self):
try:
return self.appointment_set.all().order_by('-date')[0]
except IndexError:
pass
and call this from the template:
{{ promotion.get_last_appointment.date|date }}
The cause of your problem is what #Daniel pointed out: Querysets do not support negative indexing. His solution is worth exploring.
Another way of addressing this is to add a custom filter that will work with lists and querysets. Something like:
#register.filter
def custom_last(value):
last = None
try:
last = value[-1]
except AssertionError:
try:
last = value.reverse()[0]
except IndexError:
pass
return last
And in the template:
{% with appointments|custom_last as last_ap %}