How to switch design for each cards in django templates - django

How to switch between different card designs for each data in the for loop.
<div class="col-1-of-3">
<div class="card">
...
</div>
</div>
<div class="col-1-of-3">
<div class="card">
...
</div>
</div>
<div class="col-1-of-3">
<div class="card">
...
</div>
</div>
These three cards have different designs, Currently facing trouble in switching these cards for each loop in the Django template.
{% for cont in data %}
{% ifequal forloop.counter|divisibleby:"3" True %}
<div class="col-1-of-3">
<div class="card">
...
</div>
</div>
{% endifequal %}
{% ifequal forloop.counter|divisibleby:"2" True %}
<div class="col-1-of-3">
<div class="card">
...
</div>
</div>
{% endifequal %}
{% ifnotequal forloop.counter|divisibleby:"2" True %}
<div class="col-1-of-3">
<div class="card">
...
</div>
</div>
{% endifnotequal %}
{% endfor %}
Third card logic is wrong. I need to change this logic so that for each loop each cards need to be displayed alternatively. And another challenge is that after 3 loop it should close the section, since in a row only 3 cards are allowed.
<section class="section-tours" id="section-tours">
{% ifequal forloop.counter|divisibleby:"3" True %}
{% endifequal %}
{% ifequal forloop.counter|divisibleby:"2" True %}
{% endifequal %}
{% ifequal forloop.counter|divisibleby:"2" True %}
{% endifequal %}
</section>

You can use build in django cycle template tag for this. You can update your html and add the cycle template tag like below to change design of 1st, 2nd and 3rd card.
{% for cont in data %}
<div class="{% cycle 'col-1-of-3' 'col-2-of-3' 'col-3-of-3' %}">
<div class="card">
...
</div>
</div>
{% endfor %}
I hope this will help you :)

Section is closed after printing 3 cards.
<section class='section-tours' id='section-tours'>
<div class="row">
{% for cont in data %}
{% cycle 'tools/col-1-of-3.html' 'tools/col-2-of-3.html' 'tools/col-3-of-3.html' as tmp silent %}
{% include tmp %}
{% cycle "" "" "</div> </section><section class='section-tours' id='section-tours'>" %}
{% endfor %}
</section>

Test the below code and tell me if it helps, since I have not tested it.
I have sliced the for loop for first three values, if you want to repeat the same change the slice for same code.
{% for cont in data|slice:":3" %} #i have sliced it for first three values only
{% if forloop.first %}
<div class="col-1-of-3">
<div class="card">
...
</div>
</div>
{% endif %}
{% ifequal forloop.counter|divisibleby:"2" True %}
<div class="col-1-of-3">
<div class="card">
...
</div>
</div>
{% endifequal %}
{% if forloop.last %}
<div class="col-1-of-3">
<div class="card">
...
</div>
</div>
{% endif %}
{% endfor %}

Related

Django templates avoid loop

I am working on a project and I have a slight confusion.
The Django Template index.html has following code:
<div class="carousel-item active">
{% for i in products|slice:"0:"%}
<div class="col-xs-3 col-sm-3 col-md-3">
<div class="card" style="width: 17rem;">
<div class="card-body">
{% for img in i.images.all %}
{% if forloop.counter == 1 %}
<img src={{img.img_url}} class="card-img-top" alt="...">
{% endif %}
{% endfor %}
<h6 class="card-title">{{i}}</h6>
{% for skus in i.skus.all %}
{% if forloop.counter == 1 %}
<h6 class="card-price">{{skus.price}} {{skus.currency}}</h6>
{% endif %}
{% endfor %}
Add to Cart
</div>
</div>
</div>
{% endfor %}
</div>
In this code, is there a way to eliminate the {% for skus in i.skus.all %}?
The all tag is getting all objects, but I am restricting the loop to run only one time through the if condition so that I can only get the first item.
Is there a way to eliminate the loops that have .all in them and restrict the statement to run only one time though any other way?
You can achieve by using either with tag to set a variable or direclty us as:
{% with skus=i.skus.first %}
<h6 class="card-price">{{skus.price}} {{skus.currency}}</h6
{% endwith %}
or
<h6 class="card-price">{{i.skus.first.price}} {{i.skus.first.currency}}</h6
You may be looking for the first queryset method:
<div class="card-body">
<img src={{i.images.first().img_url}} class="card-img-top" alt="...">
</div>

Django template row alternate for multiple content

I've a template design like this
<div class="row">
<div class="col-sm-8"></div>
<div class="col-sm-4"></div>
</div>
<div class="row">
<div class="col-sm-4"></div>
<div class="col-sm-8"></div>
</div>
and I've tried using this article django template rows of multiple items
But output doesnt come as required. How can I do as required.
What I've tried:
{% for item in items %}
<div class="row">
{% if forloop.counter|divisibleby:2 %}
<div class="col-sm-4"></div>
{% else %}
<div class="col-sm-8"></div>
{% endif %}
</div>
{% endfor %}
Your code produce one row per item. If I'm correct, you want 2 items per row.
{% with items_length = items|length%}
<div class="row">
{% for item in items %}
<div class="col-sm-{% cycle '4' '8'%}"></div>
{% if forloop.counter|divisibleby:2 and forloop.counter < items_length %}
</div>
<div class="row">
{% endif %}
{% endfor %}
</div>
{% endwith %}
Something like that should work.
The following is one way to do it:
{% for item in items %}
<div class="row">
{% if forloop.counter0|divisibleby:2 %}
<div class="col-sm-8"></div>
<div class="col-sm-4"></div>
{% else %}
<div class="col-sm-8"></div>
<div class="col-sm-4"></div>
{% endif %}
</div>
{% endfor %}
Notice the use of forloop.counter0.

Every 2nd and 3rd and 4th and 5th and so on

I am skipping first item and add 2 items in one Tag. This divisibleby does not work for me.
<div class=container>
<div class=row>
skip news 1
<div class=col-md-6>news2</div>
<div class=col-md-6>news3</div>
</div>
<div class=row>
<div class=col-md-6>news4</div>
<div class=col-md-6>news5</div>
</div>
....
</div>
You can use a mixture of conditions to accomplish this:
<div class=container>
{% for news in news_list %}
{% if forloop.counter > 1 %}
{% if forloop.counter|divisibleby:"2" %}
{% if forloop.counter > 2 %}
</div>
{% endif %}
<div class="row">
{% endif %}
<div class=col-md-6>{{ news }}</div>
{% endif %}
{% endfor %}
</div>
</div>

Dynamic carousel with django and bootstrap

I am working with a carousel to show some top rated products, the carousel works but I cant make work properly it seems that the problem is with the 'active' class . Each 'slide' shows 4 products.
This is my code
<div id="carousel-example" class="carousel slide hidden-xs" data-ride="carousel">
<div class="carousel-inner">
{% for p in prod %}
<div class="item {% if forloop.first %} active {% endif %}"> // here is the problem
<div class="row">
<div class="col-sm-3">
<h1>{{p.name}}</h1>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
If I don't use the forloop.first, the carousel doesn't slide. And with this forloop.first, it shows only one item per slide, instead of 4 items.
The output in the inspector is :
<div class="carousel-inner">
<div class="item active">
<div class="row">
<div class="col-sm-3"> // Here I expect 4 columns and I get only 1
</div>
</div>
</div>
<div class="item">
<div class="row">
<div class="col-sm-3">
</div>
</div>
</div>
</div>
Your issue is that you're trying to make a slide per each product: for each iteration of your loop you're creating a new item and put one col-sm-3 into it.
You can change your view to pass a nested structure to template or try to do something like:
<div id="carousel-example" class="carousel slide hidden-xs" data-ride="carousel">
<div class="carousel-inner">
{% for p in prod %}
{% cycle 'yes' '' '' '' as slidestart silent %}
{% if slidestart %} <div class="item {% if forloop.first %} active {% endif %}"> <div class="row">{% endif %}
<div class="col-sm-3">
<h1>{{p.name}}</h1>
</div>
{% if slidestart %} </div></div>{% endif %}
{% endfor %}
</div>
</div>
or use forloop.counter to put your items and rows each 4th row like that:
<div id="carousel-example" class="carousel slide hidden-xs" data-ride="carousel">
<div class="carousel-inner">
{% for p in prod %}
{% if forloop.counter0|divisibleby:"4" %}<div class="item {% if forloop.first %} active {% endif %}">
<div class="row">{% endif %}
<div class="col-sm-3">
<h1>{{p.name}}</h1>
{% if forloop.counter0|divisibleby:"4" %}</div>
</div>
</div>{% endif %}
{% endfor %}
</div>
</div>
The cycle answer above was closing the item everytime. Needed an 'end' cycle. This worked for me.. Thx x3al!
<div class="carousel-inner">
{% for track in track_set.all %}
{% cycle 'start' '' '' '' '' '' as slidestart silent %}
{% cycle '' '' '' '' '' 'end' as slideend silent %}
{% if slidestart %} <div class="item {% if forloop.first %} active {% endif %}"> <div class="row">{% endif %}
<div class="col-md-2">
.. slide code ..
</div>
{% if slideend %} </div></div>{% endif %}
{% endfor %}
</div>
Try this
<div {% if forloop.first %} class="item active" {% else %} class="item" {% endif %}>
I wanted to use this code to make 3 columned carousel, but the problem was when the object_list had number of items that are not dividable by the number of columns.
For example: it works with 6 columns because 6 % 3 = 0 but it doesn't work with 5 columns because 5 % 3 != 0
The problem was the cycle never got to the slidend and stopped prematurely, so I had to change the last if statement.
<div class="bs-news-wrapper">
{% for a in articles %}
{% cycle 'start' '' '' as slidestart silent %}
{% cycle '' '' 'end' as slidend silent %}
{% if slidestart %}<div class="item{% if forloop.first %} active {% endif %}">
<div class="row">{% endif %}
<div class="col-md-4">
#content
</div>
{% if not slidend and forloop.last or slidend %}
</div>
</div>{% endif %}
{% endfor %}
</div>
The change is in this line:
{% if not slidend and forloop.last or slidend %}
I hope this helps some future dwellers.

Jinja2: Create new row for every 3 items

Currently for every article in articles a new div with class span4 is created.
Instead for each row I would like to limit it's content to three span's and create a new row once that limit has been reached. How can I best implement this?
{% extends "base.html" %}
{% block content %}
<div class="container-fluid">
<legend></legend>
<div class="row-fluid" id="main">
{% for article in articles %}
<div class="span4">
<div class="thumbnail">
<img src="http://placehold.it/300x150/483CB4">
<div class="caption">
<h4>{{ article.title }}</h4>
<p> {{ article.summary }}</p>
</div>
<legend></legend>
<a class="btn" href="#"><i class="icon-thumbs-up"></i></a>
<a class="btn" href="#"><i class="icon-thumbs-down"></i></a>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
Goal:
<div class="row">
<div class="span4">article[0]</div>
<div class="span4">article[1]</div>
<div class="span4">article[2]</div>
</div>
<div class="row">
<div class="span4">article[3]</div>
<div class="span4">article[4]</div>
<div class="span4">article[5]</div>
</div>
The best way to do this is to use the built in batch filter to break up your list into groups of three:
{% for article_row in articles | batch(3, ' ') %}
<div class="row">
{% for article in article_row %}
<div class="span4">{{ article }}</div>
{% endfor %}
</div>
{% endfor %}
You can use loop.index0 and loop.last inside the for loop. Here is the for-loop documentation.
Example:
{% extends "base.html" %}
{% block content %}
<div class="container-fluid">
<legend></legend>
<div class="row-fluid" id="main">
{% for article in articles %}
{% if loop.index0 % 3 == 0 %}
<div class="row">
{% endif %}
<div class="span4">
...
</div>
{% if loop.index0 % 3 == 2 or loop.last %}
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% endblock %}
The loop.last clause should close the last row even if there were less than 3 items. <div> should start when loop.index0 gives 0 as the remainder and should end when 2 is the remainder
Another alternative would be to group the items into rows before passing them into the template, then you can just issue two for-loops one inside the other.