How to shorten Pagination in Django - django

I have a Django project with 600 listings. I get an extremely long pagination and I would like to know how I would shorten the pagination. Maybe not show all the page numbers and replace some with ... I am using bootstrap v4 and django 1.10. I know there are modules out there I could use but I want to learn.
template
{% if product.has_other_pages %}
<div class="col-md-12 text-center">
<nav aria-label="">
<ul class="pagination">
{% if product.has_previous %}
<li class="page-item"><a class="page-link"
href="?page={{ product.previous_page_number }}">«</a>
</li>
{% else %}
<li class="page-item disabled"><a class="page-link"><span>«</span></a></li>
{% endif %}
{% for i in product.paginator.page_range %}
{% if product.number == i %}
<li class="page-item active"><a class="page-link" href="#">{{ i }} <span
class="sr-only">(current)</span></a></li>
{% else %}
<li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if product.has_next %}
<li class="page-item"><a class="page-link" aria-label="Next"
href="?page={{ product.next_page_number }}">»</a></li>
{% else %}
<li class="page-item disabled"><a class="page-link"><span>»</span></a></li>
{% endif %}
</ul>
</nav>
</div>
{% endif %}
views
def products_all(request):
products = Product.objects.order_by("-date_added")
product_count = Category.objects.annotate(num_products=Count('product')).order_by('-num_products')[:5]
company_count = Company.objects.annotate(num_products=Count('product')).order_by('-num_products')[:5]
manufacturer_count = Manufacturer.objects.annotate(num_products=Count('product')).order_by('-num_products')[:5]
total_manufacturer = Manufacturer.objects.count()
total_company = Company.objects.count()
total_categories = Category.objects.count()
paginator = Paginator(products, 50)
page = request.GET.get('page')
try:
product = paginator.page(page)
except PageNotAnInteger:
product = paginator.page(1)
except EmptyPage:
product = paginator.page(paginator.num_pages)
template = "products/all.html"
context = {'product': product,
'products': products,
'product_count': product_count,
'company_count': company_count,
'manufacturer_count': manufacturer_count,
'total_categories': total_categories,
'total_company': total_company,
'total_manufacturer': total_manufacturer
}
return render(request, template, context)

Related

Paginator won't paginate

I use Paginator for paginate my posts, i have no error, and i have the list of page in the bottom of the posts, but:
1.Post doesn't paginate correctly, i have set 5 i have more.
2. When i click on the 2 second page and 3 and etc, i have the same results of posts, i have no the next page with nexts posts.
This is my view code:
def post_all(request):
posts = Post.objects.filter().order_by('-published_date')
paginator = Paginator(posts, 5)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
categories = PostCategory.objects.all().annotate(posts_count=Count('post'))
return render(request, 'front/blog/post_all.html', {"posts":posts, "categories":categories,"page_obj":page_obj})
My template:
<!-- Pagination -->
<div class="pagination">
{% if page_obj.has_previous %}
<i class="fa fa-angle-left"></i>
{% endif %}
{{ page_obj.number }} de {{ page_obj.paginator.num_pages }}
{% if page_obj.has_next %}
<i class="fa fa-angle-right"></i>
{% endif %}
</div>
<!-- End Pagination -->
Thank u.
You could try using Class-based views.
Yours would be something like this :
views.py
from django.views.generic import (ListView)
class PostAllView(ListView):
model = Post
template_name = 'front/blog/post_all.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
ordering = ['-published_date']
paginate_by = 5
and a template.html that you can adapt to yours:
<h1>Total of posts : {{ page_obj.paginator.count }}</h1>
{% for post in posts %}
<article>
<p class="article-content">{{ post.content }}</p>
<!-- all the post related content you want to display here-->
</article>
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %}
<!-- you can adapt the class to your use-->
<a class="button" href="?page=1">First</a>
<a class="button" href="?page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a class="button-strong" href="?page={{ num }}">{{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a class="button" href="?page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="button" href="?page={{ page_obj.next_page_number }}">Next</a>
<a class="button" href="?page={{ page_obj.paginator.num_pages }}">Last</a>
{% endif %}
{% endif %}

blank page in pagination Django 3.1

I implemented the Django pagination to slice the results of the search on my site.
# views.py
def search(request):
# Keywords
if 'keywords' in request.GET:
keywords = request.GET['keywords']
if keywords:
title_list_control_valve = queryset_list.filter(title__icontains=keywords).order_by('title')
description_list_control_valve = queryset_list.filter(description__icontains=keywords).order_by('description').distinct('description')
result_list_control_valves = list(chain(title_list_control_valve,
description_list_control_valve))
result_list_control_valves_2 = list(dict.fromkeys(result_list_control_valves))
paginator = Paginator(result_list_control_valves_2, 1)
page = request.GET.get('page')
paged_queries = paginator.get_page(page)
context = {
'queries': paged_queries,
}
return render(request, 'pages/search.html', context)
else:
return render(request, 'pages/search.html')
else:
return render(request, 'pages/search.html')
the URL of the site when showing search results is :
http://localhost:8000/pages/search/?keywords=something
It works perfectly fine on the first page only. From the second page on, it shows an empty page, and the URL of the site changes to:
http://localhost:8000/pages/search/?page=2
I link to other pages in the HTML as following:
<div class="col-md-12">
{% if queries.has_other_pages %}
<ul class="pagination">
{% if queries.has_previous %}
<li class="page-item">
«
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">«</a>
</li>
{% endif %}
{% for i in queries.paginator.page_range %}
{% if queries.number == i %}
<li class="page-item active">
<a class="page-link">{{i}}</a>
</li>
{% else %}
<li class="page-item">
{{i}}
</li>
{% endif %}
{% endfor %}
{% if queries.has_next %}
<li class="page-item">
»
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">»</a>
</li>
{% endif %}
</ul>
{% endif %}
</div>
The ?keywords=something part of the URL goes away.
is it the problem?
how to make the other page's link work too?
Add keywords to your GET params. For ex. href="?page={{queries.previous_page_number}}&keywords={{request.GET.keywords}}"

Django Pagination - Object list not looping in template

I'm attempting to use pagination on my notifications page for a user (list of all notifications). When I add the code for pagination:
def notificationList(request, pk):
notifications = Notification.objects.all()
paginator = Paginator(notifications, 5)
page = request.GET.get('page')
try:
notifications = paginator.page(page)
except PageNotAnInteger:
notifications = paginator.page(1)
except EmptyPage:
notifications = paginator.page(paginator.num_pages)
context = {'notifications': notifications }
return render(request, 'user/notifications.html', context)
The result is this:
However, when I comment out all pagination related code in views.py, all the notifications appear on the page (pagination appears). So I know it's not that I'm not accessing my notification object list incorrectly/returning an empty queryset. Here is the notifications.html pagination code:
{% if notifications.has_other_pages %}
<ul class="pagination justify-content-center mb-4">
{% if notifications.has_previous %}
<li class="page-item"><a class="page-link" href="?page={{ notifications.previous_page_number }}">«</a></li>
{% else %}
<li class="disabled page-item"><span class="page-link">«</span></li>
{% endif %}
{% for i in notifications.paginator.page_range %}
{% if notifications.number == i %}
<li class="active page-item"><span class="page-link">{{ i }} <span class="sr-only page-item">(current)</span></span></li>
{% else %}
<li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if notifications.has_next %}
<li class="page-item"><a class="page-link" href="?page={{ notifications.next_page_number }}">»</a></li>
{% else %}
<li class="disabled page-item"><span class="page-link">»</span></li>
{% endif %}
</ul>
{% endif %}
Here is where I render the notifications in the template:
{% for notification in notifications %}
<div class="row">
<div class="col">
{% if notification.read == False %}
<span class="badge badge-primary">New</span>
{% elif notification.read == True %}
<span class="badge badge-success">Read</span>
{% endif %}
</div>
<div class="col">
<a class="btn btn-sm btn-info" href="{% url 'offer-details' notification.offer_id %}">View</a>
</div>
<div class="col">
{% if notification.type_of_notification == "O" %}
<p>An offer has been made for one of your repairs!</p>
{% elif notification.type_of_notification == "P" %}
<p>A payment has been made on a repair!</p>
{% elif notification.type_of_notification == "OR" %}
<p>Sorry, your offer for a repair has been rejected.</p>
{% elif notification.type_of_notification == "OC" %}
<p>An offer for your repair has been canceled!</p>
{% endif %}
</div>
<div class="col">
{{notification.created_at}}
</div>
</div>
<hr>
{% endfor %}

How to paginate bootstrap cards with django

I am getting my query results based on user selection and showing them on bootstrap cards in django. I am using django Paginator to display at max 6 results per page (currently set to 1 for testing). The problem is my Paginator is showing all the results on all the pagination pages.
Could someone please help me??
View:
def results(request):
results = []
query_city = request.GET.get('city')
print(query_city)
all_records = hotel.objects.all()
for states in all_records:
if states.confirm_approval and states.space_state == query_city:
print(states)
results.append(states)
paginator = Paginator(results,1)
page = request.GET.get('page')
try:
items = paginator.page(page)
except PageNotAnInteger:
items = paginator.page(1)
except EmptyPage:
items = paginator.page(paginator.num_pages)
index = items.number - 1
max_index = len(paginator.page_range)
start_index = index - 5 if index >= 5 else 0
end_index = index + 5 if index <= max_index - 5 else max_index
page_range = paginator.page_range[start_index:end_index]
context = {
'results':results,
'items':items,
'page_range':page_range,
}
return render(request, 'results/results.html', context)
Html Template:
% for result in results %}
{% if forloop.counter0|divisibleby:3 %} <div class="row"> {% endif %}
<div class="col">
<div class="card-deck" id="cardholder">
<div class="card" style="max-width: 20rem;">
<img class="card-img-top" src="{% static 'mainpage/img/bg/books.jpg' %}" alt="Card image cap">
<div class="card-body">
<h5 class="card-title">{{ result.hotel_name }}</h5>
</div>
<div class="card-footer">
Show more
</div>
</div>
</div>
</div>
{% if forloop.counter|divisibleby:3 or forloop.last %}</div><!-- row closing -->{% endif %}
{% endfor %}
{% if items.has_other_pages %}
<nav aria-label="">
<ul class="pagination justify-content-center">
{% if items.has_previous %}
<li class=class="page-item">
<a class="page-link"
href="?page={{items.previous_page_number}}{% if request.GET.city %}&city={{ request.GET.city }}{% endif %}"
tabindex="-1">Previous</a>
</li>
{% else %}
<li class="page-item disabled"><a class="page-link">Previous</a></li>
{% endif %}
{% for i in page_range %}
{% if items.number == i %}
<li class="page-item active"><a class="page-link" href="#">{{i}} <span
class="sr-only">(current)</span></a>
</li>
{% else %}
<li class="page-item"><a class="page-link"
href="?page={{i}}{% if request.GET.city %}&city={{ request.GET.city }}{% endif %}">{{i}}</a>
</li>
{% endif %}
{% endfor %}
{% if items.has_next %}
<li class="page-item">
<a class="page-link" aria-label="Next"
href="?page={{items.next_page_number}}{% if request.GET.city %}&city={{ request.GET.city }}{% endif %}">Next</a>
</li>
{% else %}
<li class="page-item disabled"><a class="page-link">Next</a></li>
{% endif %}
</ul>
</nav>
{% endif %}
brtt3000 from r/djangolearning helped me over redit.
This was his answer: You're looping over the wrong context variable,
change it to items.
{% for result in results %} I suspected this as soon as I saw you had
both items and results in the context :)
For anyone whos gets here, remember to pass in the paginated variable.

Django: How can I redirect to a ListView with a Pagination after submitting a form?

I am using Django bootstrap modal form and when I update some record from a paginated page it redirect to the very first page of the list view. I want to redirect it to the paginated page of the record selected/updated.
My list view with update in the left corner and pop up modal form to update it
After I Click save it will redirect to the record list without the pagination parameter, How can I add pagination parameter in success url. Please help
My views.py
def record_list(request):
queryset_list = Record.objects.filter(recorded__lte=timezone.now()).order_by('-recorded')
query = request.GET.get("q")
if query:
for term in query.split():
queryset_list = Record.objects.filter(Q(persons__last_name__icontains=term) |
Q(persons__first_name__icontains=term) |
Q(persons__middle_name__icontains=term) |
Q(title__icontains=term)
)
paginator = Paginator(queryset_list.order_by('-recorded'), 10)
page_request_var = "page"
page = request.GET.get('page', 1)
try:
queryset = paginator.page(page)
except PageNotAnInteger:
queryset = paginator.page(1)
except EmptyPage:
queryset = paginator.page(paginator.num_pages)
context = {
"record_list": queryset,
"page_request_var": page_request_var,
"title": "List",
}
return render(request, 'Bato_Cabugao/Record/record_list.html', context)
class RecordUpdateView(LoginRequiredMixin,generic.UpdateView):
template_name = 'Bato_Cabugao/Record/record_update.html'
model = Record
form_class = RecordForm
Models.py
class Record(models.Model):
title = models.CharField(max_length=200)
persons = models.ManyToManyField(Person)
details = models.TextField()
recorded = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('Bato_Cabugao:list_record')
record_list.html - pagination
{% if record_list.has_other_pages %}
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-end">
{% if record_list.has_previous %}
<li class="page-item"><a class="page-link" href="?{{ page_request_var }}={{ record_list.previous_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">«</a>
</li>
{% else %}
<li class="disabled page-item"><span class="page-link">«</span></li>
{% endif %}
{% if record_list.number|add:'-4' > 1 %}
<li class="page-item"><a class="page-link" href="?page={{ record_list.number|add:' -5' }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">…</a>
</li>
{% endif %}
{% for i in record_list.paginator.page_range %}
{% if record_list.number == i %}
<li class="page-item page-link"><span>{{ i }} <span
class="sr-only">(current)</span></span></li>
{% elif i > record_list.number|add:'-5' and i < record_list.number|add:'5' %}
<li class="page-item"><a class="page-link" href="?{{ page_request_var }}={{ i }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if record_list.paginator.num_pages > record_list.number|add:'4' %}
<li class="page-item">
<a class="page-link" href="?page={{ record_list.number|add:'5' }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">…</a>
</li>
{% endif %}
{% if record_list.has_next %}
<li class="page-item">
<a class="page-link"
href="?{{ page_request_var }}={{ record_list.next_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">»
</a>
</li>
{% else %}
<li class="page-item disabled"><span class="page-link">»</span></li>
{% endif %}
</ul>
</nav>
{% endif %}
Send the current page number along with Record data to UpdateView. Then define get_success_url method in View like below.
class RecordUpdateView(LoginRequiredMixin,generic.UpdateView):
...
def get_success_url(self):
current_page = self.request.POST.get('current_page')
return <url_to_record_list> + '?page=' + current_page
Assuming that you have the current page number in request.GET or request.POST you can construct and return the final URL that you need.