Django python pagination always displaye the first 2, and last 2 pages - python

I have some pagination for a table. I have it so that it will only show 3 pages either side of the current page. However if I am on the 5th page, The first page disappears. I am trying to set it up so that the first two and last two pages of the pagination are always visible regardless of what the current page is.
code:
{% if is_paginated %}
<div class="pagination">
{% if current_page.has_previous %}
<a class="page-link" style="font-size: 24px; padding: 2px;" href="?page={{ current_page.previous_page_number }}">«</a>
{% else %}
<a class="page-link" style="font-size: 24px; padding: 2px;" href="">«</a>
{% endif %}
{% for i in current_page.paginator.page_range %}
{% if i == 1 %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ i }}</a>
{% else %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% endif %}
{% if i == 2 %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ i }}</a>
{% else %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% endif %}
{% if i != 1 and i != 2 %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ i }}</a>
{% else %}
{% if current_page.number|add:-4 == i %}
<a class="page-link" href="">...</a>
{% endif %}
{% if current_page.number|add:3 >= i and current_page.number|add:-3 <= i %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% if current_page.number|add:4 == i %}
<a class="page-link" href="">...</a>
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% if current_page.has_next %}
<a class="page-link" style="font-size: 24px; padding: 2px;" href="?page={{ current_page.next_page_number }}">»</a>
{% else %}
<a class="page-link" style="font-size: 24px; padding: 2px;" href="">»</a>
{% endif %}
</div>
{% endif %}
Screenshot:
Update:
I have worked out a jank way of having the first two pages always showing but cannot get the last two pages to always show

I add some well place if statements to always display the first and last place.
I set it so that if i == 1 show the page in the pagination navbar. Then during the loop of i I remove the first page and last page using i != 1 and i != current_page.paginator.page_range|last.
Using current_page.paginator.page_range|last will get the last value in the range and then you do the same for the last page as you did for the first page.
Code:
{% for i in current_page.paginator.page_range %}
{% if i == 1 %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ i }}</a>
{% else %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% endif %}
{% if i != 1 and i != current_page.paginator.page_range|last %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ i }}</a>
{% else %}
{% if current_page.number|add:-4 == i %}
<a class="page-link" href="">...</a>
{% endif %}
{% if current_page.number|add:3 >= i and current_page.number|add:-3 <= i %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% if current_page.number|add:4 == i %}
<a class="page-link" href="">...</a>
{% endif %}
{% endif %}
{% endif %}
{% if i == current_page.paginator.page_range|last %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ current_page.paginator.page_range|last }}</a>
{% else %}
<a class="page-link" href="?page={{ current_page.paginator.page_range|last }}">{{ current_page.paginator.page_range|last }}</a>
{% endif %}
{% endif %}
{% endfor %}
Screenshot:

Related

Jinja template groupby sorting issue

In this code block, I have grouped by headings. But I want to sort the titles in array index order. Not alphabetically.
{% set list = widget.attributes.faq_item %}
{% for title_group in list|groupby('value.main_title') %}
<h2 class="account-sss__title">{{title_group.grouper}}</h2>
{% for item in title_group.list %}
<a href="#" class="account-sss__list--link js-link">
{{item.value.question}}
</a>
<div class="account-sss__content js-account-sss__content">
{{item.value.answer}}
</div>
{% endfor %}
{% endfor %}
I solved the problem.
{% set list = widget.attributes.faq_item %}
{% set Arr_titles = [] %}
{% for event in list %}
{% if event.value.main_title not in Arr_titles %}
{% do Arr_titles.append(event.value.main_title) %}
{% endif %}
{% endfor %}
{% for index in Arr_titles %}
<h2 class="account-sss__title">{{index}}</h2>
{% for item in list %}
{% if index == item.value.main_title %}
<a href="#" class="account-sss__list--link js-link">
{{item.value.question}}
</a>
<div class="account-sss__content js-account-sss__content">
{{item.value.answer}}
</div>
{% endif %}
{% endfor %}
{% endfor %}

PageNotAnInteger at /products/ That page number is not an integer

So I'm trying to use pagination in django, When I click on previous it takes me to localhost:8000/thatpage/?page= when it is supposed to take me to the previous page, It also gives me error on that page. I have tried handling it in my views.py but it doesn't work.
I have also tried using books_obj.previous_page_number but that doesn't work too.
I'm using Django 3.1
views.py
def showproducts(request):
oof = CartItem.objects.filter(user=request.user).values_list('book', flat=True)
lmao = OrderItem.objects.filter(user=request.user).values_list('book', flat=True)
hehe = CartItem.objects.filter(user=request.user)
category = Category.objects.all()
haha = Paginator(Book.objects.all(), 2)
page = request.GET.get('page')
if page is None or "":
page = 1
fianlprice = 0
for item in hehe:
fianlprice += item.book.price
# books = Book.objects.all()
books = haha.page(page)
return render(request, 'main/products.html', {'books':books, 'price':fianlprice, 'cart':oof, 'order':lmao, 'category':category})
products.html
<h1>Products</h1>
<h1>{{ error }}</h1>
{% if user.is_authenticated %}
<h1>Your cart currently costs ${{ price }}</h1>
{% else %}
<h1>Please login to view your cart</h1>
{% endif %}
<form method="GET" action="/search/">
<label>Choose a category</label>
<select name="category" id="category">
<option value="All" selected>All</option>
{% for name in category %}
<option value="{{ name.name }}">{{ name.name }}</option>
{% endfor %}
</select>
<input type="text" placeholder="Search here" name="search" id="search">
<button type="submit">Search</button>
</form>
{% for book in books %}
<h3>{{ book.name }}</h3>
<img src= "/media/{{ book.image }}" alt="">
<p>{{ book.description }}</p>
{% if not user.is_authenticated %}
<p>Please login</p>
{% else %}
{% if book.id in cart %}
<form method="POST" action="/removefromcartforhome/">
{% csrf_token %}
<button type="submit" name="removeid" value="{{ book.id }}">remove item from cart</button>
</form>
{% elif book.id in order %}
<h3>You already own this</h3>
{% else %}
<form method="POST" action="/addtocartforhome/">
{% csrf_token %}
<button type="submit" name="bookid" value="{{ book.id }}">Add to cart</button>
</form>
{% endif %}
{% endif %}
{% endfor %}
{% if books.has_other_pages %}
{% if books.has_previous %}
<li class="page-item">
«
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">«</a>
</li>
{% endif %}
{% for i in books.paginator.page_range %}
{% if books.number == i %}
<li class="page-item active">
<a class="page-link">{{i}}</a>
</li>
{% else %}
<li class="page-item">
{{i}}
</li>
{% endif %}
{% endfor %}
{% if books.has_next %}
<li class="page-item">
»
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">»</a>
</li>
{% endif %}
{% else %}
<p>no pages</p>
{% endif %}
Change this code from:
if page is None or "":
page = 1
to
page = request.GET.get('page', None)
if page == None or page == "":
page = 1
# or
if not page:
page = 1
Update
You can use http referee to redirect to previous page:
if not page:
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

Filters not following on pagination in Django

I'm trying to set up pagination within my Django project but I can't find a way to make the filters (ptags in my case) follow to the next pages.
Ps; I use Django-haystack with faceting for filtering.
I have a custom forms.py
from haystack.forms import FacetedSearchForm
class FacetedProductSearchForm(FacetedSearchForm):
def __init__(self, *args, **kwargs):
data = dict(kwargs.get("data", []))
self.ptag = data.get('ptags', [])
super(FacetedProductSearchForm, self).__init__(*args, **kwargs)
def search(self):
sqs = super(FacetedProductSearchForm, self).search()
if self.ptag:
query = None
for ptags in self.ptag:
if query:
query += u' OR '
else:
query = u''
query += u'"%s"' % sqs.query.clean(ptags)
sqs = sqs.narrow(u'ptags_exact:%s' % query)
return sqs
That I pass in my Views:
class FacetedSearchView(BaseFacetedSearchView):
form_class = FacetedProductSearchForm
facet_fields = ['ptags']
template_name = 'search_result.html'
paginate_by = 3
context_object_name = 'object_list'
Here's my full search_result.html:
<div>
{% if page_obj.object_list %}
<ol class="row top20" id="my_list">
{% for result in page_obj.object_list %}
<li class="list_item">
<div class="showcase col-sm-6 col-md-4">
<div class="matching_score"></div>
<a href="{{ result.object.get_absolute_url }}">
<h3>{{result.object.title}}</h3>
<h5>{{ result.object.destination }}</h5>
<img src="{{ result.object.image }}" class="img-responsive">
</a>
<div class="text-center textio">
<ul class="tagslist">
<li class="listi">
{% for tags in result.object.ptags.names %}
<span class="label label-info"># {{ tags }}</span>
{% endfor %}
</li>
</ul>
</div>
</div>
</li>
{% endfor %}
</ol>
</div>
I'm able to pass the query which is a destination to the next page by adding this at the bottom of my html:
{% if is_paginated %}
<ul class="pagination pull-right">
{% if page_obj.has_previous %}
<li><i class="fas fa-angle-left"></i>Previous page</li>
{% else %}
<li class="disabled"><span><i class="fas fa-angle-left"></i>Previous page</span></li>
{% endif %}
{% if page_obj.has_next %}
<li>See more results<i class="fas fa-angle-right"></i></li>
{% else %}
<li class="disabled"><span>See more results<i class="fas fa-angle-right"></i></span></li>
{% endif %}
</ul>
{% endif %}
{% else %}
<p> Sorry, no result found for the search term <strong>{{query}} </strong></p>
{% endif %}
But If I try to add the ptags field within the pagination code by doing &ptags like this:
{% if is_paginated %}
<ul class="pagination pull-right">
{% if page_obj.has_previous %}
<li><i class="fas fa-angle-left"></i>Previous page</li>
{% else %}
<li class="disabled"><span><i class="fas fa-angle-left"></i>Previous page</span></li>
{% endif %}
{% if page_obj.has_next %}
<li>See more results<i class="fas fa-angle-right"></i></li>
{% else %}
<li class="disabled"><span>See more results<i class="fas fa-angle-right"></i></span></li>
{% endif %}
</ul>
{% endif %}
{% else %}
<p> Sorry, no result found for the search term <strong>{{query}} </strong></p>
{% endif %}
I get this error when I go to page 2 and the selected checkboxes filters (ptags) are not following:
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/search/?q=las%20vegas&ptags=&page=2
Raised by: search.views.FacetedSearchView
How can I fix this?
Your template pagination code is removing the extra filter parameters, use this -
In your my_tags.py add this template tag:
#register.simple_tag(name='url_replace')
def url_replace(request, field, value):
d = request.GET.copy()
d[field] = value
return d.urlencode()
paginate as -
{% if is_paginated %}
<br>
<div class="row">
<div class="col-12">
<ul class="pagination float-right">
{% if page_obj.has_previous %}
<li class="page-item"><a class="page-link" href="?{% url_replace request 'page' page_obj.previous_page_number %}">«</a></li>
{% else %}
<li class="page-item disabled"><span class="page-link">«</span></li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="active page-item"><span class="page-link">{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li class="page-item"><a class="page-link" href="?{% url_replace request 'page' i %}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item"><a class="page-link" href="?{% url_replace request 'page' page_obj.next_page_number %}">»</a></li>
{% else %}
<li class="page-item disabled"><span class="page-link">»</span></li>
{% endif %}
</ul>
</div>
</div>
{% endif %}

How to customize bootstrap pagination in Django?

This is the default code for Django pagination:
{% load bootstrap4 %}
{% with bpurl=bootstrap_pagination_url|default:"" %}
<ul class="{{ pagination_css_classes }}">
<li class="prev page-item{% if current_page == 1 %} disabled{% endif %}">
<a class="page-link" href="{% if current_page == 1 %}#{% else %}{% bootstrap_url_replace_param bpurl parameter_name 1 %}{% endif %}">
«
</a>
</li>
{% if pages_back %}
<li class="page-item">
<a class="page-link" href="{% bootstrap_url_replace_param bpurl parameter_name pages_back %}">…</a>
</li>
{% endif %}
{% for p in pages_shown %}
<li class="page-item{% if current_page == p %} active{% endif %}">
<a class="page-link" href="{% if current_page == p %}#{% else %}{% bootstrap_url_replace_param bpurl parameter_name p %}{% endif %}">
{{ p }}
</a>
</li>
{% endfor %}
{% if pages_forward %}
<li class="page-item">
<a class="page-link" href="{% bootstrap_url_replace_param bpurl parameter_name pages_forward %}">…</a>
</li>
{% endif %}
<li class="last page-item{% if current_page == num_pages %} disabled{% endif %}">
<a class="page-link" href="{% if current_page == num_pages %}#{% else %}{% bootstrap_url_replace_param bpurl parameter_name num_pages %}{% endif %}">
»
</a>
</li>
</ul>
{% endwith %}
So, where should I change the code to display less number of pages. The above code was retrieved from the default code of Django-bootstrap4 pagination
Like displaying in this pattern :

Looping over items with Jinja, adding in div after every 5th item

Problem
I have a list of 100 golf courses and I'm looking to insert a div, containing an image for an ad after every fifth course. How would I go about doing this?
Update #1
content.html (Revised, newest version)
I've updated my original code snippet because off of leovp's
suggested edited below. I'm having trouble showing only {% if content.featured == "Test" %} and wondering how I should closing my if-else statement.
{% for content in COPY.courses %}
<div class="course course--featured">
<img src="" class="course__image image--region">
<div class="course__inner">
<div class="course__wrapper">
{% if content.state == "MO" %}
<p class="course__state">Missouri</p>
{% elif content.state == "IL" %}
<p class="course__state">Missouri</p>
{% endif %}
</div>
<div class="course__wrapper">
<p class="course__name name--region">{{ content.name }}</p>
</div>
<p class="course__desc">{{ content.description }}</p>
</div>
</div>
{% if loop.index % 5 == 0 %}
<div class="advertising advertising--inline">
<div class="ad ad--rect">
<div class="text-center hidden-xs">
<div id="fixed-leaderboard-region-top"
class="dfp-ad"
data-dfp-custom-pos="fixed-leaderboard-top, htf"
data-dfp-size="[728,90]">
</div>
</div>
<div class="text-center hidden-sm hidden-md hidden-lg">
<div id="fixed-leaderboard-region-top-mobile"
class="dfp-ad"
data-dfp-custom-pos="fixed-leaderboard-top, htf"
data-dfp-size="[320,50]">
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</div>
content.html (Previous, old version for comparision)
I've looked into using batch from this Stack Overflow question that seemed similar, but I'm unsure if this solves my problem?
{% for content in COPY.courses %}
{% if content.featured == "Test" %}
<div class="course__inner">
<div class="course__wrapper">
{% if content.state == "MO"%}
<p class="course__state">Missouri</p>
{% elif content.state == "IL" %}
<p class="course__state">Illinois</p>
{% endif %}
</div>
<div class="course__wrapper">
<p class="course__name name--home">{{ content.name }}</p>
</div>
<p class="course__desc">{{ content.description }}</p>
</div>
{% endif %}
{% endfor %}
While iterating, you can get the current index and check if it's divisible by 5:
{% set count = 0 %}
{% for content in COPY.courses %}
{% if content.featured == "Test" %}
<div class="course course--featured">
<img src="" class="course__image image--home">
[...]
</div>
</div>
{% set count = count + 1 %}
{% if count % 5 == 0 %}
<!-- additional content once every 5 courses -->
{% endif %}
{% endif %}
{% endfor %}
NOTE: This approach no longer works after version 2.10.
For detail see:
How to increment a variable on a for loop in jinja template?

Categories

Resources