Group images by six Django templates - python

I'm trying to make the forloop group the images into <li> of 6 plus a last li with remainder if the total number isn't a multiple of 6. Right now it doesn't do this correctly some of the tags aren't inside the li.
{% for movie in movies %}
{% if forloop.counter|divisibleby:6 %}
<li>
{% endif %}
{% if forloop.first %}
<li>
{% endif %}
<a href="{{ movie.get_absolute_url }}">
{% thumbnail movie.picture "158x215" as im %}
<img src="{{ im.url }}" alt="">
{% endthumbnail %}
<p>{{ movie.name }}</p>
</a>
{% if forloop.counter|divisibleby:6 %}
</li>
{% endif %}
{% ifequal forloop.counter 5 %}
<li>
{% endifequal %}
{% endfor %}

You can do something like this to create a new <li> element after every 6 iterations.
<li>
{% for movie in movies %}
<a href="{{ movie.get_absolute_url }}">
{% thumbnail movie.picture "158x215" as im %}
<img src="{{ im.url }}" alt="">
{% endthumbnail %}
<p>{{ movie.name }}</p>
</a>
{% if forloop.counter|divisibleby:6 %}
</li>
<li>
{% endif %}
{%endfor%}
</li>

Related

Minimise code repetition by creating a reusable template

I have a template which includes 4 different paginators that only differ in context variables (tasks_today, tasks_tomorrow, ... etc.), and I want to minimise code repetition so I don't have 4 different paginator templates.
Template:
<div class="wrapper">
<h3>Today</h3>
<table>
{% if tasks_today %}
{% for task in tasks_today %}
{% include 'todo/task_table_row.html' %}
{% endfor %}
{% include 'todo/paginator_today.html' %}
{% else %}
<p>No tasks for today.</p>
{% endif %}
</table>
<h3>Tomorrow</h3>
<table>
{% if tasks_tomorrow %}
{% for task in tasks_tomorrow %}
{% include 'todo/task_table_row.html' %}
{% endfor %}
{% include 'todo/paginator_tomorrow.html' %}
{% else %}
<p>No tasks for tomorrow.</p>
{% endif %}
</table>
<h3>Upcoming</h3>
<table>
{% if tasks_upcoming %}
{% for task in tasks_upcoming %}
{% include 'todo/task_table_row.html' %}
{% endfor %}
{% include 'todo/paginator_upcoming.html' %}
{% else %}
<p>No upcoming tasks.</p>
{% endif %}
</table>
<h3>Past</h3>
<table>
{% if tasks_past %}
{% for task in tasks_past %}
{% include 'todo/task_table_row.html' %}
{% endfor %}
{% include 'todo/paginator_past.html' %}
{% else %}
<p>No tasks in the past.</p>
{% endif %}
</table>
</div>
paginator_today:
{% load url_replace %}
{% if tasks_today %}
<div class='paginator'>
<nav aria-label="Page navigation">
<ul class="pagination">
{% if tasks_today.has_previous %}
<li class="page-item">
<a class="page-link" href="?{% url_replace page_today=1 %}" aria-label="Previous">
<span aria-hidden="true">«</span>
<span class="sr-only">begin</span>
</a>
</li>
{% endif %}
{% for n in tasks_today.paginator.page_range %}
{% if tasks_today.number == n %}
<li class="page-item active">
<span class="page-link">{{ n }}
<span class="sr-only">(current)</span>
</span>
</li>
{% elif n > tasks_today.number|add:'-3' and n < tasks_today.number|add:'3' %}
<li class="page-item">
<a class="page-link" href="?{% url_replace page_today=n %}">{{ n }}</a>
</li>
{% endif %}
{% endfor %}
{% if tasks_today.has_next %}
<li class="page-item">
<a class="page-link" href="?{% url_replace page_today=tasks_today.paginator.num_pages %}" aria-label="Next">
<span aria-hidden="true">»</span>
<span class="sr-only">end</span>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% endif %}
paginator_tomorrow:
{% load url_replace %}
{% if tasks_tomorrow %}
<div class='paginator'>
<nav aria-label="Page navigation">
<ul class="pagination">
{% if tasks_tomorrow.has_previous %}
<li class="page-item">
<a class="page-link" href="?{% url_replace page_tomorrow=1 %}" aria-label="Previous">
<span aria-hidden="true">«</span>
<span class="sr-only">begin</span>
</a>
</li>
{% endif %}
{% for n in tasks_tomorrow.paginator.page_range %}
{% if tasks_tomorrow.number == n %}
<li class="page-item active">
<span class="page-link">{{ n }}
<span class="sr-only">(current)</span>
</span>
</li>
{% elif n > tasks_tomorrow.number|add:'-3' and n < tasks_tomorrow.number|add:'3' %}
<li class="page-item">
<a class="page-link" href="?{% url_replace page_tomorrow=n %}">{{ n }}</a>
</li>
{% endif %}
{% endfor %}
{% if tasks_tomorrow.has_next %}
<li class="page-item">
<a class="page-link" href="?{% url_replace page_tomorrow=tasks_tomorrow.paginator.num_pages %}" aria-label="Next">
<span aria-hidden="true">»</span>
<span class="sr-only">end</span>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% endif %}
What can I do?
url_replace.py:
from django.utils.http import urlencode
from django import template
​
register = template.Library()
​
#register.simple_tag(takes_context=True)
def url_replace(context, **kwargs):
query = context['request'].GET.dict()
query.update(kwargs)
return urlencode(query)
You can use the with keyword to set certain variables inside your include template:
{% include 'todo/paginator.html' with tasks=tasks_today page='page_today' %}
You can then replace references to tasks_today in you paginator template to tasks, as well as the reference to page_today to page
Edit: The call to url_replace is problematic, since it uses kwargs, and a call like {% url_replace page_today = x %}, will be equivalent to a call to urlreplace(context, **{'page_today' : x}).
Simply calling url_replace with page = x will not work correctly, since it will pass a keyword argument with the name of page instead of the value of page
The naive solution would be to pass a page variable to the paginator.html and call {% urlreplace **{page : 20} %}, but the Django template engine does not allow packing kwargs.
I think the best way to go here is to create a url_replace_single function, since in this use case you only replaces one value.
To do this, you'll need to define a field and value parameter on you url_replace function:
#register.simple_tag(takes_context=True)
def url_replace(context, field, value, **kwargs):
query = context['request'].GET.dict()
query_dict = { field : value}
query.update(query_dict)
return urlencode(query)
Then call the function from your template like this:
{% url_replace field=page value=x %}
The only downside is that this will only let you replace one query parameter in your url.

Breaking or stopping a forloop.counter in django

I applied a forloop.counter to label each object numerically in a for loop But I want it to number only the first fifty(50) objects and ignore the rest. Here is my code
{% load thumbnail %}
{% for image in most_viewed %}
<div class="image">
<a href="{{ image.get_absolute_url }}">
{% thumbnail image.image "200x200" crop="10%" as im %}
<span class="forloop">**{{ forloop.counter }}**</span>
<img src="{{ im.url }}">
{% endthumbnail %}
</div>
{% endfor %}
Basically, objects 51 and above should be without numbers
You can try using slice to rewrite the for loop as
{% for image in most_viewed|slice:":50" %}
It will do the iteration for first 50 image in most_viewed.
Edit - Just saw your edit. You can try using the conditional statement forloop.counter <= 50
{% for image in most_viewed %}
<div class="image">
...
{% if forloop.counter <= 50 %}
<span class="forloop">**{{ forloop.counter }}**</span>
{% endif %}
...
</div>
{% endfor %}

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 %}

How to move paginator block to the footer?

I have developed a django application. I added a paginator block to a webpage. It is placed on the wrong position. Instead, i want it to be placed below the list which is being shown. Actually, I am displaying group list on the page. Per page, only 5 group names will be displayed. Using pagination, i did that. But the problem is i am unable to place it in a correct position. I am attaching an image of the page.
The html page for this is:
{% extends "groups/group_base.html" %}
{% block pregroup %}
<div class="col-md-4">
<div class="content">
{% if user.is_authenticated %}
<h2>
Welcome back
#{{user.username }}
</h2>
{% endif %}
<h2>Groups</h2>
<p>Welcome to the Groups Page! Select a Group with a shared interest!</p>
</div>
{% if user.is_authenticated %}
<span class="glyphicon glyphicon-plus-sign"></span> Create New Group!
{% endif %}
</div>
{% endblock %}
{% block group_content %}
<div class="col-md-8">
<div class="list-group">
{% for group in object_list %}
<a class="list-group-item" href="{% url 'groups:single' slug=group.slug %}">
<h3 class="title list-group-item-heading">{{ group.name }}</h3>
<div class="list-group-item-text container-fluid">
{{ group.description_html|safe }}
<div class="row">
<div class="col-md-4">
<span class="badge">{{ group.members.count }}</span> member{{ group.members.count|pluralize }}
</div>
<div class="col-md-4">
<span class="badge">{{ group.posts.count }}</span> post{{ group.posts.count|pluralize }}
</div>
</div>
</div>
</a>
{% endfor %}
</div>
</div>
{% block pagination %}
{% if is_paginated %}
<ul class="pagination" style="display:inline-block">
{% 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 %}
{% endblock %}
{% endblock %}
The pagination code should be inside the col-md-8 div tag like below ::
{% extends "groups/group_base.html" %}
{% block pregroup %}
<div class="col-md-4">
<div class="content">
{% if user.is_authenticated %}
<h2>
Welcome back
#{{user.username }}
</h2>
{% endif %}
<h2>Groups</h2>
<p>Welcome to the Groups Page! Select a Group with a shared interest!</p>
</div>
{% if user.is_authenticated %}
<span class="glyphicon glyphicon-plus-sign"></span> Create New Group!
{% endif %}
</div>
{% endblock %}
{% block group_content %}
<div class="col-md-8">
<div class="list-group">
{% for group in object_list %}
<a class="list-group-item" href="{% url 'groups:single' slug=group.slug %}">
<h3 class="title list-group-item-heading">{{ group.name }}</h3>
<div class="list-group-item-text container-fluid">
{{ group.description_html|safe }}
<div class="row">
<div class="col-md-4">
<span class="badge">{{ group.members.count }}</span> member{{ group.members.count|pluralize }}
</div>
<div class="col-md-4">
<span class="badge">{{ group.posts.count }}</span> post{{ group.posts.count|pluralize }}
</div>
</div>
</div>
</a>
{% endfor %}
</div>
{% block pagination %}
{% if is_paginated %}
<ul class="pagination" style="display:inline-block">
{% 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 %}
{% endblock %}
</div>
{% endblock %}

How to ignore the first item in a list in a FOR function?

I have the following for loop that spits out all photos in a list:
{% if photos %}
{% for photo in photos %}
{% thumbnail photo.photo "100x100" crop="center" as im %}
<img src="{{ im.url }}" alt="User's photos" data-ajax="{% url 'photo_increase_view' pk=photo.id %}"/>
{% endthumbnail %}
{% endfor %}
{% endif %}
How can edit this to ignore the first result in the list (i.e. display items 2, 3, 4... etc)
Use slice
Replace
{% for photo in photos %}
by
{% for photo in photos|slice:"1:" %}
So , complete code
{% if photos %}
{% for photo in photos|slice:"1:" %}
{% thumbnail photo.photo "100x100" crop="center" as im %}
<img src="{{ im.url }}" alt="User's photos" data-ajax="{% url 'photo_increase_view' pk=photo.id %}"/>
{% endthumbnail %}
{% endfor %}
{% endif %}
Check out forloop.first using Django; for example:
{% if photos %}
{% for photo in photos %}
{% if not forloop.first %}
{% thumbnail photo.photo "100x100" crop="center" as im %}
<img src="{{ im.url }}" alt="User's photos" data-ajax="{% url 'photo_increase_view' pk=photo.id %}"/>
{% endthumbnail %}
{% endif %}
{% endfor %}
{% endif %}
I guess the answer it's a bit late. But a solution is:
{% for photo in photos[1:] %}
.....
{% endfor %}

Categories