In my django view, I pass a list that contains several items.
My html design is like this:
<ul>
<li>
<div>1st item</div>
<div>2nd item</div>
</li>
<li>
<div>3th item</div>
<div>4th item</div>
</li>
<li>
<div>5th item</div>
<div>6th item</div>
</li>
</ul>
You see the pattern, every two items, I need to split them and put into a new <li></li>. How can I loop and divide these variables by every two using {% for item in my_list %}?
You could try something like this which isn't particularly elegant and isn't tested in any way!
{% if list_of_items %}
<ul>
<li>
{% for item in list_of_items %}
<div>{{ item }}</div>
{% cycle '' '</li><li>' %}
{% endfor %}
</li>
</ul>
{% endif %}
You could re-arrange the list in your view first to make it a list of lists, or alternatively you could write your own batch filter.
As far as I know there isn't a really easy django template way of doing what you want - Django templates are deliberately restrictive to encourage you to write python code instead.
If the items have some property that groups them naturally into pairs, you can use regroup:
{% if list_of_items %}
<ul>
{% regroup list_of_items by property as item_chunks %}
{% for chunk in item_chunks %}
<li>
{% for item in chunk.list %}
{{ item }}
{% endfor %}
</li>
{% endfor %}
</ul>
{% endif %}
It's a couple more lines than Nick's solution, but if those elements do have a property that joins them naturally, I would say that this is a more elegant solution.
you might want to enumerate your total list of 6 elements in batches of size 2 which gives you 3 batches and then loop through each batch.
To do this, you can add a custom batch filter in your templatetags directory. Here is the documentation for adding custom tag/filter.
https://docs.djangoproject.com/en/1.9/howto/custom-template-tags/
Your custom filter can be something like this.
#register.filter
def batch(iterable, n=1):
l = len(iterable)
for ndx in range(0, l, n):
yield iterable[ndx:min(ndx + n, l)]
In your html
{% for batch in yourlist|batch:2%}
<li>
{% for element in batch %}
<div>{{element}}</div>
{% endfor %}
</li>
{% endfor %}
Updating this answer for Django 3.1
{% block content %}
<div class="row">
{% for product in products %}
<div class="col-md-auto">
<h5>{{ product.name }}</h5>
</div>
{% if forloop.counter|divisibleby:"6" %}
</div>
<div class="row">
{% endif %}
{% endfor %}
</div>
{% endblock content %}
Related
I am working on FAQs page where questions and answers are passed to a template sections based on their categories. I would like to reduce amount of html and use section div as a template
<div id="{{id}}">
<div class="h2">{{category}}</div>
{% for q in faqs %}
{% if q.category == '{{category}}' %}
<ul class="collapsible">
<li>
<div class="collapsible-header">{{q.question}}></div>
<div class="collapsible-body"><span>{{q.answer}}</span></div>
<div class="divider"></div>
</li>
</ul>
{% endif %}
{% endfor %}
</div>
My main html contains following code:
{% with id='m_faq'%}
{% with category='Methodology'%}
{% include 'main/faqs_section.html' %}
{% endwith %}{% endwith %}
I am only able to pass variables id and category.
Is there a way to the for loop as well?
I think the solution would be to create a list for categories in views.py
cat = [ 'Category1', 'Category2', 'Category3','Category4']
pass it to context dictionary and then put additional 'for loop' around section div.
{% for c in cat %}
<div id="">
<div class="h4">{{c}}</div>
{% for q in faqs %}
{% if c == q.category %}
<ul class="collapsible">
<li>
<div class="collapsible-header">{{q.question}}</div>
<div class="collapsible-body"><span>{{q.answer}}</span></div>
<div class="divider"></div>
</li>
</ul>
{% endif %}
{% endfor %}
</div>
{% endfor %}
That will generate a template with list of faqs divided in to sections..
I have the following html structure:
<div class="row>
<div class="box"></div>
<div class="box"></div>
</div>
I am using pagination feature on Django to pass on 6 items per page.
How would I go about iterating over the paginator generated object list while wrapper each two box divs with row div?
You can use the forloop.counter in the template
{% for obj in obj_list %}
{% if forloop.counter0|divisibleby:2 %}
<div class="row">
{% endif %}
<div class="box"></div>
<div class="box"></div>
{% if forloop.counter|divisibleby:2 %}
</div>
{% endif %}
{% else %}
Nothing to show
{% endfor %}
and if there are odd number of elements in the list, then it would not have a trailing div. I will let you figure out that scenario by yourself. (it is pretty simple)
Documentation for the forloop.counter0 can be found here
Documentation for divisibleby can be found here
I agree with karthikr's solution, but it doesn't print the </div> if you have 3, 5 items...
You have to add a forloop.last to handle that case:
{% for obj in obj_list %}
{% if forloop.counter0|divisibleby:2 %}
<div class="row">
{% endif %}
<div class="box"></div>
<div class="box"></div>
{% if forloop.counter|divisibleby:2 or forloop.last %}
</div>
{% endif %}
{% else %}
Nothing to show
{% endfor %}
i would like to create an index of lists in jekyll of all tags and the corresponding posts.
My first approach, for-loops for every tag:
<h4>FRUITY</h4>
{% for post in site.tags.fruity %}
<ul class="posts">
<li>
{{ post.title }}
</li>
</ul>
{% endfor %}
<h4>SWEET</h4>
{% for post in site.tags.sweet %}
<ul class="posts">
<li>
{{ post.title }}
</li>
</ul>
{% endfor %}
...
This WORKS, but i have to manually create a new for-loop for every new tag.
My second approach, one loop to automatize this step so i dont have to worry about new or removed tags:
{% for tag in site.tags %}
<div class="medium-6 large-3 columns list-view-all">
<h4>{{ tag | first | upcase}}</h4>
{% for post in site.posts contains tag %}
<ul class="posts">
<li>
{{ post.title }}
</li>
</ul>
{% endfor %}
</div>
{% endfor %}
The first part works, every tag becomes a header.
in the inner for-loop ALL posts containing any tag get listed. So the lists for every tag are equal.
The Question:
How can i make a list for every tag with only the posts corresponding to the respective tag?
Thanks for your help!
{% for tag in site.tags %}
<div class="medium-6 large-3 columns list-view-all">
{% assign currentTag = tag | first %}
<h4>{{ currentTag | upcase}}</h4>
{% for post in site.posts %}
{% if post.tags contains currentTag %}
<ul class="posts">
<li>
{{ post.title }}
</li>
</ul>
{% endif %}
{% endfor %}
</div>
{% endfor %}
I need to represent collection in the template and wrap every four elements in the
<li></li>
The template should be like this:
<ul>
<li>
<a></a>
<a></a>
<a></a>
<a></a>
</li>
<li>
<a></a>
<a></a>
<a></a>
<a></a>
</li>
<li>
<a></a>
<a></a>
<a></a>
<a></a>
</li>
</ul>
So i need to do it in the {% for %}
{% for obj in objects %}
{#add at 1th and every 4th element li wrap somehow#}
<a>{{object}}</a>
{# the same closing tag li#}
{% endfor %}
The following should solve your problem, using built-in template tags :
<ul>
<li>
{% for obj in objects %}
<a>{{ obj }}</a>
{# if the the forloop counter is divisible by 4, close the <li> tag and open a new one #}
{% if forloop.counter|divisibleby:4 %}
</li>
<li>
{% endif %}
{% endfor %}
</li>
</ul>
You can use the divisibleby tag as mentioned before, but for template clearing purposes I usually prefer a helper function that returns a generator:
def grouped(l, n):
for i in xrange(0, len(l), n):
yield l[i:i+n]
example simplistic view:
from app.helpers import grouped
def foo(request):
context['object_list'] = grouped(Bar.objects.all(), 4)
return render_to_response('index.html', context)
example template:
{% for group in object_list %}
<ul>
{% for object in group %}
<li>{{ object }}</li>
{% endfor %}
</ul>
{% endfor %}
you can use divisibleby built-in filter, here is link to django documentation
so something like this would work
{% if value|divisibleby 4 %}
#your conditional code
{% endif %}
if you want to work it with checking first forloop and last forloop you could use this :
<ul>
{% for obj in objects %}
{% if forloop.first %}
<li>
{% endif %}
<a>{{obj}}</a>
{% if forloop.counter|divisibleby:4 and not forloop.first %}
</li>
<li>
{% endif %}
{% if forloop.last %}
</li>
{% endif %}
{% endfor %}
</ul>
I personally would consider to separate the elements in the view before passing them to the template and then using nested for loops. Except this you really only have the filter or templatetag option as Vaibhav Mishra mentioned.
When there is a dictionary:
menu = {'title': 'Link1',
'children': {'title': 'Child of Link1',
'children': #etc..}
}
How would one iterate over it so that the output becomes:
<ul>
<li>Link1
<ul>
<li>Child of Link 1
<ul>
<li>Grandchild of Link 1
<ul>etc..</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
Currently I use this, but it obviously only goes to a depth of one.
<ul id="mainnavigation">
{% for k,v in admin.items %} #ContextProcessor, because this menu needs to know the current path.
<li class="expandable">{{ v.title }}
{% if v.children != None %}
<ul>
{% for id,child in v.children.items %}
<li class="expandable">{{ child.title }}</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
One way would be to manually repeat the loop for each level, however such a solution is ugly and I am hoping there is a more DRY one.
You'll have to make custom template tag for this. I would choose inclusion tag.
{% for k,v in var %}
{% my_tag v.children %}
{% endfor %}
If you already know that every part is just going to have title & children for each, why not just do nested tuples? You can then just use the built in filter, unordered_list.
So, it'd be:
menu = (Link 1 (Child of Link 1 (Grandchild of Link 1 (...) )))
and
<ul id="mainnavigation">
{{ menu|unordered_list }}
</ul>