Django {% if forloop.first %} question - python

I have the following code in my template:
{% for object in object_list %}
{% with game=object.game %}
{% for category in object.game.objectmeta.categories.all %}
{% if category.name|title == 'Puzzle' %}
{% if forloop.first %}
<div class='side_header' id='dark_gamelink_side'>
<a class='actionheader' href=""></a>
</div>
{% endif %}
<div class='game_link' id='dark_gamelink'>
<a class='img_link' href="{% url game_view game.id game.title|slugify %}">
<img class='game_img' src='{{game|thumb:"78x65"}}' alt='{{game.title}}' />
</a>
<div class='top_game_title' style='padding:0'>
<a style='position:relative; top:-3px' id='yellowlink' href="{% url game_view game.id game.title|slugify %}">{{game.title}} -- {{category.name|title}}</a>
<img style='position:relative; top:1px; margin-left:12px' src='thumbsup.gif' width='17' height='18'/>
<span style='position:relative; top:-3px; font-size:10px; color:white'>99%</span>
</div>
{% if game.description|length > 65 %}
{{ game.description|slice:"65" }}...
{% else %}
{{ game.description }}
{% endif %}
</div>
{% if forloop.counter0 == 3 %}
<div class='more_games'><br/></div><div class='side_header' id='dark_gamelink_side'><a class='adventureheader' href=adventure.htm></a></div>
{% endif %}
{% endif %}
{%endfor%}
{% endwith %}
{% endfor %}
Now I'm using this:
{% if forloop.first %}
<div class='side_header' id='dark_gamelink_side'>
<a class='actionheader' href=""></a>
</div>
{% endif %}
to try to detect if this is the first iteration of the for loop immediately preceding it not the parent forloop. In other words I'm trying to detect if it's the 1st iteration of this for loop:
{% for category in object.game.objectmeta.categories.all %}
not this one:
{% for object in object_list %}
The way it is now isn't working because it's displaying this:
<div class='side_header' id='dark_gamelink_side'>
<a class='actionheader' href=""></a>
</div>
Twice. How to detect the first iteration of the nested forloop?

Edited:
I have never used these variables but I think forloop.parentloop.first should do it. If not blame me to have misunderstand the Django docs. ;-)
You should check if you are within the parentloop and and then within the first nested node. Please try this modified template. It should you give the right direction.
{% if forloop.parentloop.first %}
I am in the first loop of the parent
{% else %}
{% if forloop.first %}
<div class='side_header' id='dark_gamelink_side'>
<a class='actionheader' href=""></a>
</div>
{% endif %}
{% endif %}

I think the best way to solve this isn't to detect if this is the first iteration in the loop, but rather to write your HTML so that is outside the loop entirely.
You should only be writing HTML elements in the for loop that you actually want repeated for each iteration. If that doesn't work, rethink how you're providing the data to your view (object_list, game, category, etc) so that you can write your markup more easily.
The beginning of your view will probably look something like this:
<div class='side_header' id='dark_gamelink_side'>
<a class='actionheader' href=""></a>
</div>
{% for object in object_list %}
{% with game=object.game %}
{% for category in object.game.objectmeta.categories.all %}
{% if category.name|title == 'Puzzle' %}

Related

How to use two separate block tags on the same template

I am trying to create a template for a blog landing page. Basically, I am trying to extend certain features from my base template, so I have two block tags that I want to appear at different parts of the page. Here is the first block tag;
{% extends 'index.html' %}
{% block content %}
{% for politic in politics %}
<div class="post-entry-1 col-lg-4 box mx-1">
<img src="{{politic.image.url}}" alt="" class="post_img">
<div class="post-meta">
<span class="date">{{politic.category}}</span>
<span class="mx-1">&bullet;</span>
<span>{{politic.created_at}}</span>
</div>
<h2 class="mb-2">{{politic.title}}</h2>
<span class="author mb-3 d-block">Ole Pundit</span>
<p class="mb-4 d-block">{{politic.body|truncatewords:75}}</p>
</div>
{% endfor %}
{% endblock %}
But once the number of blog posts uploaded (politics.count) reaches 4, I want the for loop in the first block tag to break. And the following block tag to be executed;
{% block sidepolitics %}
{% if politics.count > 4 %}
{% for politic in politics %}
<div class="post-entry-1 border-bottom">
<div class="post-meta">
<span class="date">{{politic.category}}</span>
<span class="mx-1">&bullet;</span>
<span>{{politic.created_at}}</span>
</div>
<h2 class="mb-2">
<a href="single-post.html">{{politic.title}}
</a>
</h2>
<span class="author mb-3 d-block">Ole Pundit</span>
</div>
{% endfor %}
{% endif %}
{% endblock %}
Meaning the maximum number of blogposts that should follow the first layout is four, and the rest should all follow the second layout.
Both blog tags are nested under the political.html file below
{% extends 'index.html' %}
{% block content %}
{% for politic in politics %}
<div class="post-entry-1 col-lg-4 box mx-1">
<img src="{{politic.image.url}}" alt="" class="post_img">
<div class="post-meta">
<span class="date">{{politic.category}}</span>
<span class="mx-1">&bullet;</span>
<span>{{politic.created_at}}</span>
</div>
<h2 class="mb-2">{{politic.title}}</h2>
<span class="author mb-3 d-block">Ole Pundit</span>
<p class="mb-4 d-block">{{politic.body|truncatewords:75}}</p>
</div>
{% endfor %}
{% endblock %}
{% block sidepolitics %}
{% if politics.count > 4 %}
{% for politic in politics %}
<div class="post-entry-1 border-bottom">
<div class="post-meta">
<span class="date">{{politic.category}}</span>
<span class="mx-1">&bullet;</span>
<span>{{politic.created_at}}</span>
</div>
<h2 class="mb-2">
<a href="single-post.html">{{politic.title}}
</a>
</h2>
<span class="author mb-3 d-block">Ole Pundit</span>
</div>
{% endfor %}
{% endif %}
{% endblock %}
And here is my base template **index.html;
<div class="d-flex align-items-end">
{% block content %}
{% endblock %}
</div>
</div>
<div class="col-md-3">
{% block sidepolitics %}
{% endblock %}
</div>
**view.py
from django.shortcuts import render
from .models import Post, Politics
from django.views.generic import DetailView
# Create your views here.
def index(request):
return render(request, 'index.html')
def allposts(request):
posts = Post.objects.all()
return render(request, 'allposts.html', {'posts':posts})
def political(request):
politics = Politics.objects.all()
return render(request, 'political.html', {'politics':politics})
def post(request, pk):
posts = Post.objects.get(id=pk)
return render(request, 'posts.html', {'posts':posts})
The problem is, for both for loops the application starts iterating from the very beginning. How can I make the first for loop to iterate only up to the fourth count, and the second for loop to pick up right where the first loop leaves off.
Firstfully, if you want to count objects, you need to use .count in template:
{% if politics > 4 %} # good for integers or similar
{% if politics.count > 4 %} # good for querysets
Secondly, you need to understand standard pythonish for loops because {% for politics in politics %} just makes absolutely no sense. It works like this:
{% for politic in politics %} # usually it's like this: {% for SINGULAR in PLURAL %}
otherwise you are overriding politics variable and it should not work, at least not good.
Second loop makes no sense at all, I guess you don't need it.
With that said and your edits, use forloop.counter. It returns int with the current loop round. Here's hint:
{% for item in item_list %}
{{ forloop.counter }} # starting index 1
{{ forloop.counter0 }} # starting index 0
{% endfor %}
Instead of {% if politics.count > 4 %} that now I understand you don't need, use above logic. In first loop:
{% for politic in politics %}
{% if forloop.counter < 5 %}
# whole first for loop here
{% else %}
# whole second for loop here
{% endif %}
{% endfor %}

Django class based view pagination not working

I am trying to use a pagination to paginate one of my pages. I have tried a few different methods I have found online but for some reason, when I use paginate_by = 3, it doesn't actually paginate anything, yet still shows the html for the pagination at the bottom of the page.
View:
class SearchListView(ListView):
model = Post
template_name = "public/search.html"
paginate_by = 3
HTML:
{% extends 'public/base.html' %}
{% load staticfiles %}
{% block head %}
<link rel="stylesheet" type="text/css" href="{% static "public/css/search.css" %}" />
{% endblock %}
{% block content%}
<div class="search container-fluid">
<img src="/media/about-us.jpg" alt="">
<div class="search-title">
<h1 class="title">Search</h1>
</div>
<div class="search-main mb-5">
<form method='GET' action=''>
<input type="text" name='q' class="homebanner-search" placeholder="Enter your keywords" value='{{ request.get.q }}'>
</form>
</div>
</div>
<div class="container mt-5 mb-5">
<div class="detail-container">
{% for post in queryset %}
<a href="{% url 'post-detail' post.slug %}">
<div class="post-main">
<div class="post-image">
<img src="{{ post.image.url }}" class="card-img-top" alt="#">
<p class="post-category">{{ post.category }}</p>
</div>
<div class="post-body">
<div class="post-title">
<p class="post-title-p">Day in the life of {{ post.title }}</p>
</div>
<div class="post-text">
<p class="post-author-text text-muted">{{ post.sub_description|truncatewords:22 }}</p>
</div>
<div class="post-button">
<p>READ MORE ></p>
</div>
</div>
</div>
</a>
{% endfor %}
</div>
<div id="page_navigation" >
{% if is_paginated %}
<ul class="pagination">
{% if page_obj.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
</div>
</div>
{% endblock %}
So on the page, 3 items should be showing, and pagination should take me to the the next set of 3. The html is showing, and when I click the links it is taking me 2 page 2. The problem is the fact that 6 items are showing, and not 3, and when I go to page 2, there are the same 6 items there.
Unfortunately I couldn't reproduce your error exactly, but what did happen is that my objects wouldn't render when looping through queryset. So what I would recommend is try to loop through object_list instead:
{% for post in object_list %}
{{ post.name }}
{% endfor %}
Another thing you can do is add a context_object_name argument to your view:
class SearchListView(ListView):
model = Post
template_name = "public/search.html"
paginate_by = 3
context_object_name = 'posts'
and then loop through that:
{% for post in posts %}
{{ post.name }}
{% endfor %}
Also, I can't visualise what the search form is doing on this page since the ListView's model (Post) is the queryset, not whatever is searched for? So perhaps the link href is causing some trouble. Maybe try something like this instead:
<li>«</li>
Again, I could not reproduce the exact problem you are having, which is a shame because I feel like I have had the same issue before, so these are just suggestions pieced together from pagination that works for me and the code you posted. Hope it points you in the right direction.

Is it possible to custom django-tables2 template for a specific page in this case?

I'm using django-tables2 to render my data in tables in the template..
everything is rendered fine with pagination..
The Designer of our company wants to change the Display of data into blocks instead of simple table. the following picture may explain more.
I Want to ask if I can use Django tables2 in this case ..since I don't want to loose the pagination
Is it possible to custom the django_tables2/table.html file to only fit this case (because I'm using django-tables2 in many other pages in the project)?
Any other ideas may be helpful.
Thanks in advance :)
Yes, you can create a custom template (based on django_tables2/table.html) and set a specific table's template Meta attribute to its path:
import django_tables2 as tables
class Table(tables.Table):
# columns
class Meta:
template = 'table-blocks.html'
or use the template argument to the Table constructor:
table = Table(queryset, template='table-blocks.html')
or use the second argument of the {% render_table %} templatetag:
{% load django_tables2 %}
{% render_table queryset 'table-blocks.html' %}
I was having the same requirement and i had been able to do it. To achieve the desired results i have used bootstrap4 and modified the "django_tables2/bootstrap4.html" template. My modified template only displays blocks which can further be enhanced by embedding more css in it.
{% load django_tables2 %}
{% load i18n %}
{% block table-wrapper %}
<div class="container-fluid relative animatedParent animateOnce p-0" >
{% block table %}
{% block table.tbody %}
<div class="row no-gutters">
<div class="col-md-12">
<div class="pl-3 pr-3 my-3">
<div class="row">
{% for row in table.paginated_rows %}
{% block table.tbody.row %}
<div class="col-md-6 col-lg-3 my-3">
<div class="card r-0 no-b shadow2">
{% for column, cell in row.items %}
<div class="d-flex align-items-center justify-content-between">
<div class="card-body text-center p-5">
{% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %}{{ cell|localize }}{% else %}{{ cell|unlocalize }}{% endif %}{% endif %}
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock table.tbody.row %}
{% empty %}
{% if table.empty_text %}
{% block table.tbody.empty_text %}
<tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
{% endblock table.tbody.empty_text %}
{% endif %}
{% endfor %}
</div></div></div> </div>
{% endblock table.tbody %}
{% block table.tfoot %}
{% if table.has_footer %}
<tfoot {{ table.attrs.tfoot.as_html }}>
<tr>
{% for column in table.columns %}
<td {{ column.attrs.tf.as_html }}>{{ column.footer }}</td>
{% endfor %}
</tr>
</tfoot>
{% endif %}
{% endblock table.tfoot %}
{% endblock table %}
</div>
{% block pagination %}
{% if table.page and table.paginator.num_pages > 1 %}
<nav aria-label="Table navigation">
<ul class="pagination justify-content-center">
{% if table.page.has_previous %}
{% block pagination.previous %}
<li class="previous page-item">
<a href="{% querystring table.prefixed_page_field=table.page.previous_page_number %}" class="page-link">
<span aria-hidden="true">«</span>
{% trans 'previous' %}
</a>
</li>
{% endblock pagination.previous %}
{% endif %}
{% if table.page.has_previous or table.page.has_next %}
{% block pagination.range %}
{% for p in table.page|table_page_range:table.paginator %}
<li class="page-item{% if table.page.number == p %} active{% endif %}">
<a class="page-link" {% if p != '...' %}href="{% querystring table.prefixed_page_field=p %}"{% endif %}>
{{ p }}
</a>
</li>
{% endfor %}
{% endblock pagination.range %}
{% endif %}
{% if table.page.has_next %}
{% block pagination.next %}
<li class="next page-item">
<a href="{% querystring table.prefixed_page_field=table.page.next_page_number %}" class="page-link">
{% trans 'next' %}
<span aria-hidden="true">»</span>
</a>
</li>
{% endblock pagination.next %}
{% endif %}
</ul>
</nav>
{% endif %}
{% endblock pagination %}
{% endblock table-wrapper %}

Python / Django - have a certain number of items in a loop wrapped in a div

I have a simple for loop in Django, outputting a series of teaser stories. Each is wrapped in a div with a class of row. I have an varibale called num_of_rows, that adds a class of hidden after 2 loops, which hides these divs from view with css.
Here's my code:
{% block content %}
<h1>{{ section.title }}</h1>
{% for story in story_list %}
<div class="row {% if num_of_rows > 2 %} hidden{% endif %}">
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
</a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
</div>
{% endfor %}
{% endblock %}
What I'd like to do is, instead of adding a class of hidden to each individual row, wrap all of the items after 2 items in a separate div and then hide with CSS from that, using Django. This way I can create a much smoother slide-down effect with jQuery.
You can use the forloop variables for this:
{% for story in story_list %}
{% if forloop.counter == 3 %}<div class="hidden">{% endif %}
<div class="row">
<h2>
<a href="{{ story.get_absolute_url }}">
{{ story.headline|upper }}
</a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
</div>
{% if forloop.counter > 2 and forloop.last %}</div>{% endif %}
{% endfor %}

Pagination problem with Django haystack

i'm using django-haystack with simple engine, the search is fine, but the pagination is not working. This is the code of my search results template
{% if query %}
<br>
<div id="contenido_pagina">
{% for result in page.object_list %}
{% if result.object.get_model == '[Video] ' %}
{% if result.object.publicar %}
<div class="salida_search">
{{result.object.get_model}}{{result.object.nombre}}<br>
<div class="resumen_search">
{{result.object.sinopsis|safe|truncatewords:"30"}}
</div>
<div class="link_search">
{{result.object.anio}}
</div>
</div>
{% endif %}
{% else %}
<div class="salida_search">
{{result.object.get_model}}{{result.object.titulo}}<br>
<div class="resumen_search">
{% if result.object.contenido %}
{{result.object.contenido|safe|truncatewords:"30"}}
{% else %}
{{result.object.sinopsis|safe|truncatewords:"30"}}
{% endif %}
</div>
<div class="link_search">
{{result.object.fecha|date:"d M Y"}}
</div>
</div>
{% endif %}
{% empty %}
<div>La busqueda <span class="highlighted">{{query}}</span> no obtuvo ningun resultado</div>
{% endfor %}
{% if page.has_previous or page.has_next %}
<div>
{% if page.has_previous %}{% endif %}« Anterior{% if page.has_previous %}{% endif %}
|
{% if page.has_next %}{% endif %}Siguiente »{% if page.has_next %}{% endif %}
</div>
{% endif %}
</div>
<br>
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
when i go to the next page i see the same objects that first page. What i am doing wrong??
I had this issue as well. From debugging the code it looks like it's an issue with the paginator and the searchqueryset. Unfortunately i didn't have more time to devote to it and ended up moving on to whoosh for development environment.
Just encountered this. Seems as though it's a known limitation of the simple backend.
https://github.com/toastdriven/django-haystack/issues/320

Categories