How to break "for loop" in Django template - django

I have this code
{% for account in object_list %}
<tr>
{% for field, value in book.get_fields %}
<th>{{ field.verbose_name }}</th>
{% endfor %}
</tr>
{{ break }}
{% endfor %}
I want to break the for loop after first iteration. break is not working

I think you should use slice to achieve your goal
{% for account in object_list|slice:":1" %}

There is no break in Django template system. Django template system is not programmed with python but with its own language.
Depending on what you need to do, you might find this question useful. Otherwise, just put the one and only account you are trying to print on HTML on a special field on your RequestContext.

You can't use break statement but you can choose not to print them on html. It's not a best solution but you can use it. I use the following one;
{%for tumbnail in image %}
{%if tumbnail.object_id == element.id %}
<img src="/media/{{ tumbnail.image }}" class="tr_all_hover"alt="">
{{ "<!--" }}
{%endif%}
{%endfor%}
{{ "-->" }}
Its basicly seem like this on browser.
http://i.stack.imgur.com/MPbR3.jpg

{% for i in list %}
{% if forloop.counter < 11 %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ i.product__name }}</td>
<td>{{ i.brand__name }}</td>
<td>{{ i.country__name}}</td>
<td>{{ i.city__name}}</td>
</tr>
{% endif %}
{% endfor %}

You can use your Django template system for loop in javascript for loop as inner loop and can use break as follows :-
for(var i=0;i<1;i++){
{% for owner in Owner %}
id = "{{owner.id}}";
if(id == pk1){
f="{{owner.flat}}";
break;
}
{% endfor %}
}

I found a way to do this with a condition. It's ugly and hacky, but it works (for me). first is what the OP wanted, but this answers the actual question more closely.
Given this:
obj = {
'children': [
{ 'possessions' : { 'toys': [] } },
{ 'possessions' : { 'toys': ['train'] } }
{ 'possessions' : { 'toys': ['train', 'ball'] } }
]
}
I wanted to know if my obj has any children with possessions that are toys.
Here's what I did:
Python Equivalent:
if ([child for child in obj.children if child.possessions.toys]):
# Whatever
Django Template:
My approach was to use regroup to build sets of candidates which did or didn't match the criteria:
{% regroup obj.children by possessions.toys|length_is:"0" as by_toys %}
{% for check in by_toys %}{% if check.grouper == False %}
Whatever
{% endif %}{% endfor %}
regroup builds a new object that is essentially:
[
{ 'grouper': '', 'list': [/*...*/] },
{ 'grouper': True, 'list': [/*...*/] },
{ 'grouper': False, 'list': [/*...*/] }
]
The length_is:"0" makes sure that we have at most three elements in that list and the grouper is either True or False or ''. Then we iterate over the list and check for a False value.
If there are no children it'd be an empty list and the if would never be hit.
If no children have toys, it'd be a list without a False grouper.
If all children have toys, it'd be a list with a False grouper.
If some children have toys, it'd be a list with False and True groupers.

In this case you can check if forloop.counter == 1 or if forloop.first and simply print that first item.
{% for account in object_list %}
{% if forloop.first %}
<tr>
{% for field, value in book.get_fields %}
<th>{{ field.verbose_name }}</th>
{% endfor %}
</tr>
{% endif %}
{% endfor %}

There is no break in Django template system but you can achieve an statement like break with bellow architecture. (Loop will go iteration but u don't do anything.)
1- Use with to define a variable to determine current status,
2- Use a template custom tag to change statement to negate current status.
in template use like this:
{% with statement=1 %}
{% for obj in listObject %}
{% if ifStatement and statement %}
{% changeStatement statement as statement %} // when u don't want to enter in if again.
Do your job here!!
{% endif %}
{% endfor %}
{% endwith %}
In template custom tags :
#register.simple_tag
def changeStatement(status):
return not status

Slicing is the best as mentioned on top!
Alternatively, you can use a template variable for more complex continue/breaks:
How can I use break and continue in Django templates?

Related

django template for loop if nothing found for specific hostname create a blank cell

I am aggregating multiple outputs from models into the same table. So I am looking for a hostname_id, which ties the models together, and then displaying the output. The problem is there may not be data to display which throws off the alignment of the table so I need to create blank cells.
{% for y in cpuAverageReport %}
{% if x.id == y.hostName_id %}
<td>{{ y.average | floatformat:0}}%</td>
<td>{{ y.maximum | floatformat:0}}%</td>
{% endif %}
{% endfor %}
So if, at the end of the loop, the if argument is never matched I want to create two blank cells. I tried using {% with var="something" %} to tag when the if argument is matched but the {% endwith %} tag must be before the endif tag rendering it useless...
I would say figure out if there's matches in the view and then pass it to the template. From what I'm reading the template shouldn't be handling stuff like this and it should be in the view
I looked into template tags, but at the end of the day it's not much different that figuring it out in the view and passing it to the template
Like you I looked into using with and that's a no-go, unfortunately, as you cant change the values of a with :( bummer!
Finally you could do a JavaScript onload: check if table has rows, if not: create one it's iffy style wise, but it would work.
Could you not just add on an {% else %} with the empty cells to the end of the {% if %} statement?
{% for y in cpuAverageReport %}
{% if x.id == y.hostName_id %}
<td>{{ y.average | floatformat:0}}%</td>
<td>{{ y.maximum | floatformat:0}}%</td>
{% else %}
<td></td>
<td></td>
{% endif %}
{% endfor %}

Django template jinja for loop

Can someone suggest me how to iterate a dictionary in django template?
dic1={5: ['jaw replacement - 23-Jun-2020 (16:20:09.164240)', 'jaw replacement done - 23-Jun-2020 (16:20:51.158085)', 'jaw replacement done,almost done - 23-Jun-2020 (16:25:40.066955)', 'jaw replacement done,almost done 1 - 23-Jun-2020 (16:27:00.355605)', 'jaw replacement done,almost done 2 - 23-Jun-2020 (16:31:35.111660)']}
this is the context i am passing
i need something like this in template
for i in dic1:
print(i)
list1=dic1[i]
for k in list1:
print(k)
{% for i in notes %}
{% with list1=dic1[i] %}
{{list1}}
{% endwith %}
{% endfor %}
This is not working.
Lets say your data is -
dic1 = {'a': [ [1, 2] ], 'b': [ [3, 4] ],'c':[ [5,6]] }
You can use the data.items() method to get the dictionary elements. Note, in django templates we do NOT put (). Also some users mentioned values[0] does not work, if that is the case then try values.items.
<table>
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
{% for key, values in dic1.items %}
<tr>
<td>{{key}}</td>
{% for v in values[0] %}
<td>{{v}}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
I hope It helps you.
In normal Python you would normally access keys and values by using the items() method on a dictionaty.
For example given the dictionary
some_dic = {'1': 'Hello', '2': 'World'}
You should be able to access this by doing the following:
for key, value in some_dic.items():
print(key, value)
You can follow this same principle in Django templates and simply omit the '()' as follows:
{% for key, value in some_dic.items %}
<h1>Key: {{ key }}</h1>
<h1>Value: {{ value }}</h1>
{% endfor %}
you can pass dic1 one directly to the template from view and iterate through dictionary in template \
in view
return render(request, 'template.html',{'dic1':dic1})
#intemplate.html
{% for key, value in dic1 %}
<tr>
<td> Key: {{ key }} </td>
{% for value_in_array in value %}
<td> Value: {{ value }} </td>
{% endfor %}
</tr>
{% endfor %}

Check whether value in dict with for loop in Django's template

I have the following data in my views.
months = [1,2,3,4,5,6,7,8,9,10,11,12]
mydict = {3:'a',4:'b'}
The key means month,if this month exists value,then render the value,else leave blank.
Here's my template.
{% for j in months %}
{% if mydict.j %}
<th class="align-middle">{{ mydict.j }}</th>
{% else %}
<th class="align-middle"></th>
{% endif %}
{% endfor %}
But the result always is blank.
I can access the value by mydict.3,but i can't get the value by mydict.j with a forloop.
If you write {{ mydict.j }}, then Django aims to lookup the value mydict['j'], not mydict[j].
Dictionary lookups and function calls (with arguments) are deliberately not allowed in a template, such that developers are encouraged to write business logic in the view not in the template. You can write a custom template filter, or make use of the jinja template renderer to allow this.
But it might be more sensical to do the mapping in the view:
def some_view(request):
mydict = {3:'a',4:'b'}
monthsanddict = [(x, mydict.get(x)) for x in range(1, 13)]
return render(request, 'some_template.html', {'monthsanddict': monthsanddict})
and in the template, you can then render this with:
{% for j, mydictj in monthsanddict %}
{% if mydictj %}
<th class="align-middle">{{ mydictj }}</th>
{% else %}
<th class="align-middle"></th>
{% endif %}
{% endfor %}

Using forloop.counter value as list index in a Django template

in my Django 1.1.1 application I've got a function in the view that returns to his template a range of numbers and a list of lists of items, for example:
...
data=[[item1 , item2, item3], [item4, item5, item6], [item7, item8, item9]]
return render_to_response('page.html', {'data':data, 'cycle':range(0,len(data)-1])
Inside the template I've got an external for loop, that contains also another for cycle to display in output the contains of the inner lists of data in this way
...
{% for page in cycle %}
...
< table >
{% for item in data.forloop.counter0 %}
< tr >< td >{{item.a}} < /td > < td > {{item.b}} ... < /td > < /tr >
...
< /table >
{% endfor %}
{% if not forloop.last %}
< div class="page_break_div" >
{% endif %}
{% endfor %}
...
But Django template engine doesn't work with the forloop.counter0 value as index for the list (instead it does if I manually put a numeric value as index). Is there a way to let the list loop works with the external forloop.counter0 value?
Thanks in advance for the help :)
I solved this in a rather inefficient way. Please don't throw up on your computer when you read this code. Given two lists of identical length, it will iterate through the first and print the corresponding item from the second.
If you must use this, only use it for rarely-accessed templates where the length of both lists will be small. Ideally, refactor your template's data to avoid this problem altogether.
{% for list1item in list1 %}
{% for list2item in list2 %}
{% if forloop.counter == forloop.parentloop.counter %}
{{ list1item }} {{ list2item }}
{% endif %}
{% endfor %}
{% endfor %}
You can't use variables for attribute names, dictionary keys or list indices.
Also range(0,len(data)-1] is not valid python. It should be range(len(data)).
You probably don't need cycle. Maybe what you want is this:
{% for itemlist in data %}
...
<table>
{% for item in itemlist %}
<tr>
<td>{{ item.a }}</td>
<td>{{ item.b }} ... </td>
</tr>
...
{% endfor %}
</table>
{% if not forloop.last %}
<div class="page_break_div">
{% endif %}
{% endfor %}
I wanted to have alternating colours in my table using a style sheet, by passing a list of toggling True/False values. I found this really frustrating. In the end I created a list of dictionary items with the same keys as the fields in the table, plus one more with the toggling true/false value.
def jobListView(request):
# django does not allow you to append stuff to the job identity, neither
# will it allow forloop.counter to index another list. The only solution
# is to have the toggle embedded in a dictionary along with
# every field from the job
j = job.objects.order_by('-priority')
# have a toggling true/false list for alternating colours in the table
theTog = True
jobList = []
for i in j:
myJob = {}
myJob['id'] = i.id
myJob['duty'] = i.duty
myJob['updated'] = i.updated
myJob['priority'] = i.priority
myJob['description'] = i.description
myJob['toggle'] = theTog
jobList.append(myJob)
theTog = not(theTog)
# next i
return render_to_response('index.html', locals())
# end jobDetaiView
and my template
{% if jobList %}
<table border="1"><tr>
<th>Job ID</th><th>Duty</th><th>Updated</th><th>Priority</th><th>Description</th>
</tr>
{% for myJob in jobList %}
<!-- only show jobs that are not closed and have a positive priority. -->
{% if myJob.priority and not myJob.closeDate %}
<!-- alternate colours with the classes defined in the style sheet -->
{% if myJob.toggle %}
<tr class=d1>
{% else %}
<tr class=d0>
{% endif %}
<td><a href="/jobs/{{ myJob.id }}/">{{ myJob.id }}</td><td>{{ myJob.duty }}</td>
<td>{{ myJob.updated }}</td><td>{{ myJob.priority }}</td>
<td class=middle>{{ myJob.description }}</td>
</tr>
{% endif %}
{% endfor %}
</ul>
{% else %}
<p>No jobs are in the system.</p>
{% endif %}
Use forloop.last - True if this is the last time through the loop:
{% if forloop.last %}
{% endif %}
From Built-in template tags and filters

Numeric for loop in Django templates

How do I write a numeric for loop in a Django template? I mean something like
for i = 1 to n
I've used a simple technique that works nicely for small cases with no special tags and no additional context. Sometimes this comes in handy
{% for i in '0123456789'|make_list %}
{{ forloop.counter }}
{% endfor %}
{% with ''|center:n as range %}
{% for _ in range %}
{{ forloop.counter }}
{% endfor %}
{% endwith %}
Unfortunately, that's not supported in the Django template language. There are a couple of suggestions, but they seem a little complex. I would just put a variable in the context:
...
render_to_response('foo.html', {..., 'range': range(10), ...}, ...)
...
and in the template:
{% for i in range %}
...
{% endfor %}
My take on this issue, i think is the most pythonic. Create a my_filters.py in your apps templatetags directory.
#register.filter(name='times')
def times(number):
return range(number)
Usage in your template:
{% load my_filters %}
{% for i in 15|times %}
<li>Item</li>
{% endfor %}
You can pass a binding of
{'n' : range(n) }
to the template, then do
{% for i in n %}
...
{% endfor %}
Note that you'll get 0-based behavior (0, 1, ... n-1).
(Updated for Python3 compatibility)
Maybe like this?
{% for i in "x"|rjust:"100" %}
...
{% endfor %}
I'm just taking the popular answer a bit further and making it more robust. This lets you specify any start point, so 0 or 1 for example. It also uses python's range feature where the end is one less so it can be used directly with list lengths for example.
#register.filter(name='range')
def filter_range(start, end):
return range(start, end)
Then in your template just include the above template tag file and use the following:
{% load myapp_filters %}
{% for c in 1|range:6 %}
{{ c }}
{% endfor %}
Now you can do 1-6 instead of just 0-6 or hard coding it. Adding a step would require a template tag, this should cover more uses cases so it's a step forward.
You can pass :
{ 'n' : range(n) }
To use template :
{% for i in n %}
...
{% endfor %}
I tried very hard on this question, and I find the best answer here:
(from how to loop 7 times in the django templates)
You can even access the idx!
views.py:
context['loop_times'] = range(1, 8)
html:
{% for i in loop_times %}
<option value={{ i }}>{{ i }}</option>
{% endfor %}
You don't pass n itself, but rather range(n) [the list of integers from 0 to n-1 included], from your view to your template, and in the latter you do {% for i in therange %} (if you absolutely insist on 1-based rather than the normal 0-based index you can use forloop.counter in the loop's body;-).
Just incase anyone else comes across this question… I've created a template tag which lets you create a range(...): http://www.djangosnippets.org/snippets/1926/
Accepts the same arguments as the 'range' builtin and creates a list containing
the result of 'range'.
Syntax:
{% mkrange [start,] stop[, step] as context_name %}
For example:
{% mkrange 5 10 2 as some_range %}
{% for i in some_range %}
{{ i }}: Something I want to repeat\n
{% endfor %}
Produces:
5: Something I want to repeat
7: Something I want to repeat
9: Something I want to repeat
You should use "slice" in template, a example like this:
in views.py
contexts = {
'ALL_STORES': Store.objects.all(),
}
return render_to_response('store_list.html', contexts, RequestContext(request, processors=[custom_processor]))
in store_list.html:
<ul>
{% for store in ALL_STORES|slice:":10" %}
<li class="store_item">{{ store.name }}</li>
{% endfor %}
</ul>
This method supports all the functionality of the standard range([start,] stop[, step]) function
<app>/templatetags/range.py
from django import template
register = template.Library()
#register.filter(name='range')
def _range(_min, args=None):
_max, _step = None, None
if args:
if not isinstance(args, int):
_max, _step = map(int, args.split(','))
else:
_max = args
args = filter(None, (_min, _max, _step))
return range(*args)
Usage:
{% load range %}
<p>stop 5
{% for value in 5|range %}
{{ value }}
{% endfor %}
</p>
<p>start 5 stop 10
{% for value in 5|range:10 %}
{{ value }}
{% endfor %}
</p>
<p>start 5 stop 10 step 2
{% for value in 5|range:"10,2" %}
{{ value }}
{% endfor %}
</p>
Output
<p>stop 5
0 1 2 3 4
</p>
<p>start 5 stop 10
5 6 7 8 9
</p>
<p>start 5 stop 10 step 2
5 7 9
</p>
This essentially requires a range function. A Django feature ticket was raised (https://code.djangoproject.com/ticket/13088) for this but closed as "won't fix" with the following comment.
My impression of this idea is that it is trying to lead to programming in the template. If you have a list of options that need to be rendered, they should be computed in the view, not in the template. If that's as simple as a range of values, then so be it.
They have a good point - Templates are supposed to be very simple representations of the view. You should create the limited required data in the view and pass to the template in the context.
{% for _ in ''|center:13 %}
{{ forloop.counter }}
{% endfor %}
If the number is coming from a model, I found this to be a nice patch to the model:
def iterableQuantity(self):
return range(self.quantity)
You can use:
{% with ''|center: i as range %}
For those who are looking to simple answer, just needing to display an amount of values, let say 3 from 100 posts for example just add {% for post in posts|slice:"3" %} and loop it normally and only 3 posts will be added.
This shows 1 to 20 numbers:
{% for i in "x"|rjust:"20"|make_list %}
{{ forloop.counter }}
{% endfor %}
also this can help you:
(count_all_slider_objects come from views)
{% for i in "x"|rjust:count_all_slider_objects %}
{{ forloop.counter }}
{% endfor %}
or
{% with counter=count_all_slider_objects %}
{% if list_all_slider_objects %}
{% for slide in list_all_slider_objects %}
{{forloop.counter|add:"-1"}}
{% endfor%}
{% endif %}
{% endwith %}
You can pass range(n) instead of n in the context in views.py. This will give you an iterable list.
context['range']= range(n)
Then you can iterate in your template this way:
{% for i in range %}
<!-- your code -->
{% endfor %}
{% for i in range(10) %}
{{ i }}
{% endfor %}