Efficient way to pass list to template for bootstrap grid - flask

What is the best practice to pass data from routes to template so that it doesn't break the template?
I have a template that uses bootstrap grid that is N rows by 3 columns.
Currently I am calculating the number of rows required in routes, and passing a list to the template to iterate through using Jinja2. I am doing this because I can't seem to import Math in the template, or perform some of the basic python operations like len(mylist)
As a result of this "hack", I have to identify the elements using 3*row + i. It works, but this hard-coding is triggering my OCD!
Can any more seasoned developers share what you would do for such cases?
#app.route('grid')
def grid():
items = Items.query.all()
items_row = list(range(0, ceil(len(items)/3) )) # Because I cannot round-up on Jinja2
...
return render_template('grid.html', items=items, item_rows=item_rows)
{% for row in item_rows %}
{% if 3*row + 0 < items|length %}
<div class="row">
<div class="col-lg-4">
<a href="{{ url_for('item', id=items[3*row + 0].id) }}"
<h1>{{ items[3*row + 0].header }}</h1>
</a>
<a href="{{ url_for('item', id=items[3*row + 0].id) }}"
<p>{{ items[3*row + 0].body }}</p>
</a>
</div>
</div>
{% endif %}
{% if 3*row + 1 < items|length %}
<div class="row">
<div class="col-lg-4">
<a href="{{ url_for('item', id=items[3*row + 1].id) }}"
<h1>{{ items[3*row + 1].header }}</h1>
</a>
<a href="{{ url_for('item', id=items[3*row + 1].id) }}"
<p>{{ items[3*row + 1].body }}</p>
</a>
</div>
</div>
{% endif %}
{% if 3*row + 2 < items|length %}
<div class="row">
<div class="col-lg-4">
<a href="{{ url_for('item', id=items[3*row + 2].id) }}"
<h1>{{ items[3*row + 2].header }}</h1>
</a>
<a href="{{ url_for('item', id=items[3*row + 2].id) }}"
<p>{{ items[3*row + 2].body }}</p>
</a>
</div>
</div>
{% endif %}

I've refactored my code:
It is much more concise now
It is also much harder to read / understand
{% set rows = 3 %}
{% set cols = 3 %}
{% for item in items %}
{% if loop.index0 // rows != (loop.index0 - 1) // rows %}
<div class="row">
{% endif %}
<div class="col-lg-4 col-md-6 col-sm-12 col-xs-12">
<a href="{{ url_for('item.html', id=item.id) }}">
<h1>{{ item.header }}<h1>
</a>
<p>{{ item.body }}</p>
</div>
{% if loop.index0 % cols == 2 %}
</div>
{% endif %}
{% endfor %}

Related

How can I reset a forloop.counter0 in django?

I have a code in django that creates a carousel for each card item. As I am looping through each image for each specific card, I realized the forloop.counter will keep continuing until the initial for loop has finished. So in my example, i is my initial loop and p is my secondary loop. i loops through cards and p loops through images within the carousel of each card. I need to reset the counter after one i so that the carousel counter starts from the beginning so that first image of every carousel is active.
I'd really appreciate any help
{% for i in inspections %}
<div class="card - mb-3" style="width: 40 rem;">
<div id="myCarousel" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-indicators">
{% for p in photos.all %}
{% if p.inspection_id == i.id %}
<button type="button" data-bs-target="#myCarousel"
data-bs-slide-to="{{ forloop.counter0 }}"
class="{% if forloop.counter0 == 0 %} active {% endif %}"
aria-current="true"
aria-label="Slide {{forloop.counter0}}"></button>
{% endif %}
{% endfor %}
</div>
<div class="carousel-inner">
{% for p in photos.all %}
{% if p.inspection_id == i.id %}
<div class="carousel-item {% if forloop.counter0 == 0 %} active {% endif %}">
<img src="{{ p.InspImages.url }}"
class="img-responsive mx-auto d-block w-80" height="300"
alt="...">
</div>
{% endif %}
{% endfor %}
</div>
<button class="carousel-control-prev" type="button"
data-bs-target="#myCarousel" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="True"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button"
data-bs-target="#myCarousel" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="True"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
<div class="card-body">
# body codes #
{% endfor %}

Customize next page in Django (pagination)

so I'm building a website in Django which have similarities with YouTube. I mean there will be some thumbnails and when you click on one of them it takes you to a page where the video will be played.
Now coming to the code since I don't wanna have to hard-code everything I opted to use the pagination but I have a problem cuz the pagination is doing everything automatically and I can't change the thumbnails for the next page. So either my analysis is wrong or there a way to do it correctly.
Here's the code for the template:
{% load static %}
{% block content %}
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3 mb-5">
<div class="col">
<div class="card shadow-sm">
<a href="{% url 'watch1' %}" target="_blank"> <img src="{% static 'thumbnails/hacker.jpeg' %}" height="225"
width="100%"></a>
<div class="card-body">
<p class="card-text">
{% for element in page_obj %}
{% if element.category == 'boxing' %}
{{ element.description|truncatechars:50 }}
{% endif %}
{% endfor %}
</p>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
</div>
<small class="text-muted">9 mins</small>
</div>
</div>
</div>
</div>
<div class="col">
<div class="card shadow-sm">
<a href="{% url 'watch2' %}" target="_blank"> <img src="{% static 'thumbnails/hydra.jpg' %}" height="225"
width="100%"></a>
<div class="card-body">
<p class="card-text">
{% for element in page_obj %}
{% if element.category == 'boxing' %}
{{ element.description|truncatechars:50 }}
{% endif %}
{% endfor %}
</p>
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
</div>
<small class="text-muted">9 mins</small>
</div>
</div>
</div>
</div>
<div class="col">
<div class="card shadow-sm">
<a href="{% url 'watch3' %}" target="_blank"> <img src="{% static 'thumbnails/darkweb.jpg' %}" height="225"
width="100%"></a>
<div class="card-body">
<p class="card-text">
{% for element in page_obj %}
{% if element.category == 'boxing' %}
{{ element.description|truncatechars:50 }}
{% endif %}
{% endfor %}
<div class="d-flex justify-content-between align-items-center">
<div class="btn-group">
</div>
<small class="text-muted">9 mins</small>
</div>
</div>
</div>
</div>
</div>
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div>
{% endblock%}
the function in the view
def boxing(request):
videos = Video.objects.all()
paginator = Paginator(videos, 3) # shows 3 videos per page
pageNumber = request.GET.get('page')
try:
page_obj = paginator.get_page(pageNumber)
except:
page_obj = paginator.get_page(1)
return render(request, 'boxing.html', {'page_obj': page_obj})
And my loop is also displaying the same thing for everything. I could just use an if statement to pick exactly which video I want but with the pagination happening it'll do the same thing on the next page as well.

Posts list page, Django Wagtail

I am making a news site, there is a page where all articles are displayed. But if there are many articles, then the page will be huge.
my code :
{% block content %}
<div class=" container" style="margin-top: 60px;">
{% for post in posts %}
<div class="row" style="padding-top: 30px ">
<div class="col-sm-3">
{% image post.preview_image fill-250x250 as blog_img %}
<img style="border-radius: .3525rem" href="{{ post.url }}" src="{{ blog_img.url }}">
</div>
<div class="col-sm-9">
<a href="{{ post.url }}">
{{ post.title }}
</a>
<br/>
<p> {{ post.intro }}</p>
</div>
</div>
{% endfor %}
</div>
{% endblock content %}
what i want to do
I recommend using pagination : https://learnwagtail.com/tutorials/how-to-paginate-your-wagtail-pages/

2 Rows and 3 columns using bootstrap in Django

Trying to iterate multiple posts through a loop, into 2 rows of 3 items.
Currently my code looks like this
{% for post in post.all %}
<div class="row">
<div class="col-md-4">
<div class="thumbnail">
<div class="caption">
<h3>{{ post.title }} - {{post.assignment_level}}</h3>
<p>by {{post.author}} from {{post.pub_date}}</p>
<h4>{{post.assignment_body}}</h4>
<p>Read...</p>
</div>
</div>
</div>
</div>
{% endfor %}
{% endblock%}
this gives me one column of 6 posts.
How do I split them in to 2 rows of three posts.
Really been googling this.
Thank you in advance
You can do something like this:
{% set count = 0 %}
{% for post in post.all %}
{% if count == 0 %}
<div class="row">
{% endif %}
<div class="col-md-4">
<div class="thumbnail">
<div class="caption">
<h3>{{ post.title }} - {{post.assignment_level}}</h3>
<p>by {{post.author}} from {{post.pub_date}}</p>
<h4>{{post.assignment_body}}</h4>
<p>Read...</p>
</div>
</div>
</div>
{% set count = count + 1 %}
{% if count == 3 %}
</div>
{% set count = 0; %}
{% endif %}
{% endfor %}
{% endblock%}
What you are doing here is creating multiple rows for each posts. Hence all your elements are coming in separate rows.
You can do something like this.
<div class="row">
{% for post in post.all %}
<div class="col-md-4">
<div class="thumbnail">
<div class="caption">
<h3>{{ post.title }} - {{post.assignment_level}}</h3>
<p>by {{post.author}} from {{post.pub_date}}</p>
<h4>{{post.assignment_body}}</h4>
<p>Read...</p>
</div>
</div>
</div>
{% endfor %}
</div>

if tag does not works in django template

I have a template. Its quite simple and working fine. but if I use {% if %} tag then the if tag does not works. Instead the if tag works like a string and prints itself in browser. I cant get the cause.
{% verbatim %}
<div ng-if="pageViewing == 'list'" class="gd-content-body transparent gd-cart-checkbox-style">
</div>
<div ng-if="pageViewing == 'grid'" class="gd-content-body transparent gd-cart-checkbox-style">
<div class="row">
<article ng-repeat="item in results" resource_id="{{ item.id }}" ng-cloak class="ng-cloak">
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4">
<div class="information">
<div class="top-content text-center">
<div class="title">
<a href="{{ item.detail_url }}" title="{{ item.title }}">
{{ item.title | limitTo: 45 }}{{ item.title.length > 45 ? '...' : ''}}
</a>
</div>
<div class="category">
{{ item.category__gn_description }}
{{ item.category__gn_description == null || item.category__gn_description == '' ? 'Not provided.' : '' }}
</div>
<div class="details">
{{ item.abstract | limitTo: 300 }}{{ item.abstract.length > 300 ? '...' : ''}}
</div>
<div>
{% if item.title %}
{{ item.title }}
{% endif %}
</div>
</div>
</div>
</div>
</article>
</div>
</div>
{% endverbatim %}
You've wrapped the whole thing in {% verbatim %} so Django will never process any of the tags inside it.