Django3 Paginator with function based view - python

class ProductList(ListView):
model = Product
paginate_by = 8
def company_page(request, slug):
...
product_list = Product.objects.filter(company=company).order_by('-pk')
paginator = Paginator(product_list, 4)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'product/product_list.html', {
...,
'product_list': product_list,
'page_obj': page_obj
})
views.py
<nav aria-label="Pagination">
<ul class="pagination justify-content-center my-5">
{% if page_obj.has_previous %}
<li class="page-item mx-auto lead">
<a class="page-link" href="?page={{page_obj.previous_page_number}}" tabindex="-1" aria-disabled="true">
Newer</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">
Newer</a>
</li>
{% endif %}
{% if page_obj.has_next %}
<li class="page-item mx-auto lead">
<a class="page-link" href="?page={{page_obj.next_page_number}}">
Older</a>
</li>
{% else %}
<li class="page-item disabled mx-auto lead">
<a class="page-link" href="#!">
Older</a>
</li>
{% endif %}
</ul>
</nav>
product_list.html
I added pagination on ProductList view with paginated_by and imported Paginator to make other pages using a function view but it's only paginated on ProductList view and doesn't work on company_page view. The Newer & Older buttons work but the page keeps showing every product_list objects. How can I make it work on all pages?

Try this:
views.py
# other views ...
def company_page(request, slug):
product_list = Product.objects.filter(company=company).order_by('-pk')
page = request.GET.get('page', 1)
paginator = Paginator(product_list, 4)
try:
Products = paginator.page(page)
except PageNotAnInteger:
Products = paginator.page(1)
except EmptyPage:
Products = paginator.page(paginator.num_pages)
context = {'Products': Products}
return render(request, 'product/product_list.html', context)
product_list.html
<nav aria-label="Pagination">
{% if Products.has_other_pages %}
<ul class="pagination justify-content-center my-5">
{% if Products.has_previous %}
<li class="page-item mx-auto lead">
<a class="page-link" href="?page={{ Products.previous_page_number }}" tabindex="-1" aria-disabled="true">
Previous</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">
Previous</a>
</li>
{% endif %}
{% for i in Products.paginator.page_range %}
{% if Products.number == i %}
<li class="page-item mx-auto lead">
<a class="page-link" href="?page={{ i }}">
{{ i }}</a>
</li>
{% endif %}
{% endfor %}
{% if Products.has_next %}
<li class="page-item mx-auto lead">
<a class="page-link" href="?page={{ Products.next_page_number }}">
Next</a>
</li>
{% else %}
<li class="page-item disabled mx-auto lead">
<a class="page-link" href="#!">
Next</a>
</li>
{% endif %}
</ul>
{% endif %}
</nav>

Related

FieldError at /category_list

I am facing this probelm in my e-commerce project when i try to pagination
Cannot resolve keyword '' into field. Choices are: created_at, description, id, is_active, subcategories, thumbnail, title, url_slug
# CATEGORIES
class CategoriesListView(ListView):
model = Categories
template_name = "admin_local/category_list.html"
paginate_by = 3
def get_queryset(self):
filter_val = self.request.GET.get("filter", "")`enter code here`
order_by = self.request.GET.get("orderby", "id")
if filter_val != "":
cat = Categories.objects.filter(
Q(title__contains=filter_val) | Q(description__contains=filter_val)).order_by(order_by)
else:
cat = Categories.objects.all().order_by(order_by)
return cat
def get_context_data(self, **kwargs):
context = super(CategoriesListView, self).get_context_data(**kwargs)
context["filter"] = self.request.GET.get("filter", "")
context["orderby"] = self.request.GET.get("orderby", "")
context["all_table_fields"] = Categories._meta.get_fields()
return context
I am facing this probelm in my e-commerce project when i try to pagination
This Is html file
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<nav aria-label="Page navigation example">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item"><a class="page-link"
href="{% url 'category_list' %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.previous_page_number }} ">Previous</a>
</li>
{% else %}
<li class="page-item disabled"><a class="page-link"
href="#">Previous</a>
</li>
{% endif %}
<li class="page-item"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
{% if page_obj.has_next %}
<li class="page-item"><a class="page-link"
href="{% url 'category_list' %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.next_page_number }} ">Next</a>
</li>
{% else %}
<li class="page-item disabled"><a class="page-link"
href="#">Previous</a>
</li>
{% endif %}
</ul>
</nav>
</div>
</div>
</div>
</div>
The reason you get this is because you use orderby={{ orderby }} which is empty if it is not filled in.
You should pass the context with:
context['orderby'] = self.request.GET.get('orderby', 'id')
furthermore you should |urlencode the parameters:
<a class="page-link" href="{% url 'category_list' %}?filter={{ filter|urlencode }}&orderby={{ orderby|urlencode }}&page={{ page_obj.next_page_number }} ">Next</a>
You might also want to avoid ordering by an arbitrary field, since ordering can expose sensitive information, for example trying to order by the (hashed) password of a user.

Pagination button not highlighting the current page

So I'm trying to make a button which highlights as active when the page is the same as page number, but it does not work, It only highlights page 1, When I go to page 2 then page 1 is still highlighed, index function handles the page I'm talking about.
views.py
from django.shortcuts import render
from .models import Listing
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
# Create your views here.
def index(request):
listings = Listing.objects.all()
paginator = Paginator(listings, 3)
page = request.GET.get('page')
paged_listings = paginator.get_page(page)
params = {'listings':paged_listings}
return render(request, 'listings/listings.html', params)
def listing(request, listing_id):
return render(request, 'listings/listing.html')
def search(request):
return render(request, 'listings/search.html')
listings.html
{% extends 'base.html' %}
{% block content %}
{% load humanize %}
<!-- Breadcrumb -->
<section id="bc" class="mt-3">
<div class="container">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="{% url 'index' %}">
<i class="fas fa-home"></i> Home</a>
</li>
<li class="breadcrumb-item active"> Browse Listings</li>
</ol>
</nav>
</div>
</section>
<!-- Listings -->
<section id="listings" class="py-4">
<div class="container">
<div class="row">
{% if listings %}
{% for listing in listings %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="card listing-preview">
<img class="card-img-top" src="{{ listing.photo_main.url }}" alt="">
<div class="card-img-overlay">
<h2>
<span class="badge badge-secondary text-white">${{ listing.price | intcomma}}</span>
</h2>
</div>
<div class="card-body">
<div class="listing-heading text-center">
<h4 class="text-primary">{{ listing.title }}</h4>
<p>
<i class="fas fa-map-marker text-secondary"></i>{{ listing.city }} {{ listing.state }}, {{ listing.zipcode }}</p>
</div>
<hr>
<div class="row py-2 text-secondary">
<div class="col-6">
<i class="fas fa-th-large"></i>Sqfit: {{ listing.sqft }}</div>
<div class="col-6">
<i class="fas fa-car"></i>Garage: {{ listing.garage }}</div>
</div>
<div class="row py-2 text-secondary">
<div class="col-6">
<i class="fas fa-bed"></i>Bedrooms: {{ listing.bedrooms }}</div>
<div class="col-6">
<i class="fas fa-bath"></i>Bathrooms: {{ listing.bathrooms }}</div>
</div>
<hr>
<div class="row py-2 text-secondary">
<div class="col-12">
<i class="fas fa-user"></i>{{ listing.realtor.name }}</div>
</div>
<div class="row text-secondary pb-2">
<div class="col-6">
<i class="fas fa-clock"></i>{{ listing.list_date | timesince }}</div>
</div>
<hr>
More Info
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="col-md-12">
<p>No Listings Available</p>
</div>
{% endif %}
<!-- Footer -->
<div class="row">
<div class="col-md-12">
{% if listings.has_other_pages %}
<ul class="pagination">
{% if listings.has_previous %}
<li class="page-item">
«
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">«</a>
</li>
{% endif %}
</ul>
{% endif %}
{% for i in listings.paginator.page_range %}
{% if listings.number == i %}
<li class="page-item active">
<a class="page-link page-item">{{ i }}</a>
</li>
{% else %}
<li class="page-item">
{{i}}
</li>
{% endif %}
{% endfor %}
</div>
</div>
</div>
</section>
{% endblock %}
You mistyped argument in page links. Just replace
<li class="page-item">
{{i}}
</li>
with
<li class="page-item">
{{i}}
</li>
(difference is equal sign = between query parameter and value)
The problem seems to be your use of
{% for i in listings.paginator.page_range %}
As this is returning a range, I think you should be using:
{% for i in listings.paginator %}

Django paginator issue

I am currently working on a django blog and I've coded a search bar where you type something and, if there's any post that contains what you've typed in the title, it should appear all the posts. This part is perfectly well-written. However, there's an error with the pagination. As you'll see in the views.py. The maximum num of posts per page is 3. However, you can see there's four. However, the paginator detects there should be another page for the fourth posts. Here's an image that shows that.
Here's the views.py:
class ElementSearchView(View):
elements_list = Element.objects.all()
def get(self, request, *args, **kwargs):
paginator = Paginator(self.elements_list, 3)
page_request_var = 'page'
page = request.GET.get(page_request_var)
try:
paginated_queryset = paginator.page(page)
except PageNotAnInteger:
paginated_queryset = paginator.page(1)
except EmptyPage:
paginated_queryset = paginator.page(paginator.num_pages)
queryset = Element.objects.all()
query = request.GET.get('q')
if query:
queryset = queryset.filter(
Q(title__icontains=query)
).distinct()
context = {
'query': queryset,
'queryset': paginated_queryset,
'page_request_var': page_request_var,
}
return render(request, 'periodic/search_results_table.html', context)
And here's the html template: The pagination is at the end of the template.
{% load static %}
<html>
{% include 'periodic/head_search.html' %}
<body>
{% include 'periodic/header.html' %}
<br>
<br>
<div class="container">
<div class="row">
<!-- Latest Posts -->
<main class="posts-listing col-lg-8">
<div class="container">
<div class="row">
<!-- post -->
{% for element in query %}
<div class="post col-xl-6 wrap-login100">
<div class="post-thumbnail"><img src="{{ element.thumbnail.url }}" alt="..." class="img-fluid"></div>
<div class="post-details">
<a href="{{ element.get_absolute_url }}">
<h3 class="h4">{{ element.title }}</h3></a>
</div>
</div>
{% endfor %}
</div>
<!-- Pagination -->
<nav aria-label="Page navigation example">
<ul class="pagination pagination-template d-flex justify-content-center">
{% if queryset.has_previous %}
<li class="page-item"> <i class="fa fa-angle-left"></i></li>
{% endif %}
<li class="page-item">{{ queryset.number }}</li>
{% if queryset.has_next %}
<li class="page-item"> <i class="fa fa-angle-right"></i></li>
{% endif %}
</ul>
</nav>
{% if is_paginated %}
<nav aria-label="Page navigation example">
<ul class="pagination pagination-template d-flex justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item"> <i class="fa fa-angle-left"></i></li>
{% endif %}
<li class="page-item">{{ page_obj.number }}</li>
{% if page_obj.has_next %}
<li class="page-item"> <i class="fa fa-angle-right"></i></li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</main>
</body>
{% include 'periodic/scripts_search.html' %}
</html>
As the user #ikilnac mentioned,
you are looping over the original queryset and not the paged one in your template
That simply means that in your loop, you do this
{% for element in query %}
<div class="post col-xl-6 wrap-login100">
<div class="post-thumbnail"><img src="{{ element.thumbnail.url }}" alt="..." class="img-fluid"></div>
<div class="post-details">
<a href="{{ element.get_absolute_url }}">
<h3 class="h4">{{ element.title }}</h3></a>
</div>
</div>
{% endfor %}
And then after that, you are using the tag in the form of {% if queryset.has_previous %} with the original queryset rather than the paged one in the template (the query).
There's a good example of it here - Paginate with Django

Paginator in a view function Django

I'm trying to add the paginate option on my posts page from my blog website. I want to implement the paginator on my view function that renders the page and I found this exemple from Django's doc but it doesn't work. Any help ?
view function:
def blog(request):
posts = Post.objects.all().order_by('-date_posted')
paginator = Paginator(posts, 2)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
context = {
'posts': posts,
'page_obj': page_obj,
'title': 'Blog',
'banner_page_title': 'Blog',
'page_location': 'Home / Blog'
}
return render(request, 'blog/blog.html', context)
html rendering
<nav class="blog-pagination justify-content-center d-flex">
<ul class="pagination">
{% if is_paginated %}
{% if page_obj.has_previous %}
<li class="page-item">
<a href="?page={{ page_obj.previous_page_number }}" class="page-link" aria-label="Previous">
<span aria-hidden="true">
<span class="ti-arrow-left"></span>
</span>
</a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active">
{{ num }}
</li>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<li class="page-item">
{{ num }}
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a href="?page={{ page_obj.next_page_number }}" class="page-link" aria-label="Next">
<span aria-hidden="true">
<span class="ti-arrow-right"></span>
</span>
</a>
</li>
{% endif %}
{% endif %}
</ul>
</nav>
the url route
path('blog/', blog, name='blog'),
Remove the {% if is_paginated %} as it isn't returning any value and that is why you don't see any of the numbers (don't forget to remove the closer if {% endif %})
You can access your paginated objects from the page_obj
{% for post in page_obj %}
{{ post }}
{% endfor %}
Here is the HTML with the changes
{% for post in page_obj %}
{{ post.text }}<br>
{% endfor %}
<nav class="blog-pagination justify-content-center d-flex">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item">
<a href="?page={{ page_obj.previous_page_number }}" class="page-link" aria-label="Previous">
<span aria-hidden="true">
<span class="ti-arrow-left"></span>
</span>
</a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active">
{{ num }}
</li>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<li class="page-item">
{{ num }}
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a href="?page={{ page_obj.next_page_number }}" class="page-link" aria-label="Next">
<span aria-hidden="true">
<span class="ti-arrow-right"></span>
</span>
</a>
</li>
{% endif %}
</ul>
</nav>

Django pagination is not working properly with very large dataset

When I use pagination with a very large dataset, it works too slow. Maybe I am not implementing it properly. Please help. How to make it fast? Is there anything that I can change or implement so that it works fine?
view.py
def display(request):
user_list = Final.objects.all()
searchlen= user_list.count()
paginator = Paginator(user_list, 100)
page = request.GET.get('page')
users = paginator.get_page(page)
return render(request,'displayLogs.html',{'users': users,'searchlen':searchlen})
model.py
class Final(models.Model):
name = models.TextField(db_column='Date',primary_key=True, blank=True, null=False) # Field name made lowercase.
corr = models.TextField(db_column='CorrelationId', blank=True, null=True) # Field name made lowercase.
<tbody>
<tr class="gradeX">
{% for item in users %}
<td>{{item.dat}}</td>
<td>{{item.act}}</td>
<td>{{item.actor}}</td>
<td class="center">{{item.tar}}</td>
</tr>
{% endfor %}
</tbody>
<div class="pagination" style="border-style:inset;border-width:5px;padding-bottom: 5px">
{% if users.has_previous %}
<a class="pagination-action" href="?page=1"> <i class="fas fa-angle-double-left"></i></a>
<a class="pagination-action" href="?page={{ users.previous_page_number}}"> <i class="fas fa-angle-left"></i></a>
{% endif %}
{% for num in users.paginator.page_range %}
{% if users.number == num %}
<span class="pagination-number pagination-current"><strong>{{ num }}</strong></span>
{% elif num > users.number|add:'-3' and num < users.number|add:'3' %}
<a class="pagination-number" href="?page={{ num }}">{{num}}</a>
{% endif %}
{% endfor %}
{% if users.has_next %}
<a class="pagination-action" href="?page={{ users.next_page_number }}"><i class="fas fa-angle-right"></i></a>
<a class="pagination-action" href="?page={{ users.paginator.num_pages }}"> <i class="fas fa-angle-double-right"> </i></a>
{% endif %}
</div>
I suggest doing something like this for large dataset. I attach my design as given below. Here click << to go first page , >> to go last page , < to go previous page and > to go next page.
<tbody>
{% for item in users %}
<tr class="gradeX">
<td>{{item.dat}}</td>
<td>{{item.act}}</td>
<td>{{item.actor}}</td>
<td class="center">{{item.tar}}</td>
</tr>
{% endfor %}
</tbody>
<nav aria-label="pagination" class="pagination_area">
<div class="row">
{% if users.end_index > 0 %}
<div class="col-sm-12 col-md-5 d-none d-md-block">
<p>Showing {{ users.start_index }} to {{ users.end_index }} of {{ users.paginator.count}}.</p>
</div>
{% endif %}
{% if users.paginator.num_pages > 1 %}
<div class="col-sm-12 col-md-7 dataTables_pager">
<ul class="pagination">
{% if users.has_previous %}
<li class="page-item">
<a class="page-link" data-page="1" href="?page={{ users.previous_page_number }}">
<i class="fa fa-angle-double-left"></i>
</a>
</li>
{% if users.previous_page_number > 1 %}
<li class="page-item">
<a class="page-link " data-page="{{users.previous_page_number}}" href="?page={{ users.previous_page_number }}">
<i class="fa fa-angle-left"></i>
</a>
</li>
{% endif %}
{% endif %}
{% if users.previous_page_number > 2 %}
<li class="page-item">
<a class="page-link " data-page="{{users.number|add:'-2'}}" href="?{{users.number|add:'-2'}}"> {{ users.number|add:"-2" }} </a>
</li>
<li class="page-item">
<a class="page-link " data-page="{{users.number|add:'-1'}}" href="?page={{users.number|add:'-1'}}"> {{ users.number|add:"-1" }} </a>
</li>
{% endif %}
<li class="page-item active"><span class="page-link ">{{ users.number }}</span></li>
{% if users.paginator.num_pages > users.number|add:"2" %}
<li class="page-item">
<a class="page-link " data-page="{{users.number|add:'1'}}" href="?page={{users.number|add:'1'}}"> {{ users.number|add:"1" }} </a>
</li>
<li class="page-item">
<a class="page-link " data-page="{{users.number|add:'2'}}" href="?page={{users.number|add:'2'}}"> {{ users.number|add:"2" }} </a>
</li>
{% endif %}
{% if users.has_next %}
<li class="page-item">
<a class="page-link " data-page="{{users.next_page_number}}" href="?page={{ users.next_page_number }}">
<i class="fa fa-angle-right"></i>
</a>
</li>
<li class="page-item">
<a class="page-link " data-page="{{users.paginator.num_pages}}" href="?page={{users.paginator.num_pages}}">
<i class="fa fa-angle-double-right"></i>
</a>
</li>
{% endif %}
</ul>
</div>
{% endif %}
</div>
</nav>
This is my design. You can change design for your requirement.

Categories