I am having problems with my pagination, The number of pages i put in place (5) is not working. UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: QuerySet.
How can i change it to a class based view.
def post(request, category_slug):
categories = Category.objects.all()
post = Post.objects.all()
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
posts = post.filter(category=category).order_by('-id')
page = request.GET.get('page', 1)
paginator = Paginator(posts, 6)
try:
users = paginator.page(page)
except PageNotAnInteger:
users = paginator.page(1)
except EmptyPage:
users = paginator.page(paginator.num_pages)
print(users)
context = {
'page_obj': users,
}
<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" aria-hidden="true"></i><i class="fa fa-angle-left" aria-hidden="true"></i></li>
<li class="page-item"> <i class="fa fa-angle-left" aria-hidden="true"></i></li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item">{{ 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"> <i class="fa fa-angle-right" aria-hidden="true"></i></li>
<li class="page-item"><i class="fa fa-angle-right" aria-hidden="true"></i><i class="fa fa-angle-right" aria-hidden="true"></i></li>
{% endif %}
</ul>
</nav>
The return type from filter is a QuerySet (https://docs.djangoproject.com/en/3.0/ref/models/querysets/)
The Paginator documentation (https://docs.djangoproject.com/en/3.0/ref/paginator/#django.core.paginator.Paginator) says that it expects a list for its first argument.
The QuerySet documentation says that in order to force evaluation as a list, you can call list()
Thefore:
Paginator(post.list(), 6)
Related
I am trying to create a webpage using Django where my database consists thousands of CVEs and display the list of CVEs based on what I typed in the search bar. So far, the search function is working perfectly and it displays the paginated results. But when I try to navigate to next page, it will show a blank page. Below is the code of my views.py and template.
views.py
def search_cve(request):
if request.method == 'GET':
searched = request.GET.get('searched')
if searched:
cve_search = BDSA.objects.filter(cve_id__icontains=searched)
paginator = Paginator(cve_search.order_by('-cve_id'), 10) # show 10 per page
try:
page = int(request.GET.get('page', '1'))
except:
page = 1
try:
cves = paginator.page(page)
except:
cves = paginator.page(1)
index = cves.number - 1
max_index = len(paginator.page_range)
start_index = index - 2 if index >= 2 else 0
end_index = index + 2 if index <= max_index - 2 else max_index
page_range = list(paginator.page_range)[start_index:end_index]
return render(request, 'QueryService/search_cve.html', {'searched':searched, 'cve_search':cve_search, 'cves': cves, 'page_range': page_range})
else:
return render(request, 'QueryService/search_cve.html', {})
template
<body>
{% block content %}
<br/>
<center>
<h1>Searched for: {{ searched }}</h1>
<br/>
<div class="container">
<table class="table table-hover table-striped table-bordered">
{% for cve in cves %}
<tr>
<td>{{ cve }}</td>
</tr>
{% endfor %}
</table>
</div>
<br/>
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center">
{% if cves.has_previous %}
<li class="page-item"><a class="page-link" href="?page=1">« First</a></li>
<li class="page-item"><a class="page-link" href="?page={{ cves.previous_page_number }}">Prev</a></li>
{% endif %}
{% for pg in page_range %}
{% if cves.number == pg %}
<li class="page-item"><a class="page-link" href="?page={{ pg }}" class="btn btn-default">{{ pg }}</a></li>
{% else %}
<li class="page-item"><a class="page-link" href="?page={{ pg }}" class="btn">{{ pg }}</a></li>
{% endif %}
{% endfor %}
{% if cves.has_next %}
<li class="page-item"><a class="page-link" href="?page={{ cves.next_page_number }}">Next</a></li>
<li class="page-item"><a class="page-link" href="?page={{ cves.paginator.num_pages }}">Last »</a></li>
{% endif %}
</ul>
</nav>
<br/><br/>
</center>
{% endblock %}
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
</body>
Any idea on how to fix this?
Nevermind I got the fix! I added this code in the href element of the pagination.
&searched={{ searched }}
For example:
href="?page=1&searched={{ searched }}
I made a blog app in which I want to add pagination both on home page and category page. but after a lot of efforts I didn't get how to use it in the category page. I use 2 parameters in category view and I don' know how to fix it now. whenever I click on category "That page number is not an integer" displays.
views.py:
def allpost(request):
postData = Post.objects.all()
paginator = Paginator(postData, 5) # Show 5 contacts per page.
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'posts.html', {'page_obj': page_obj})
def CategoryView(request, cats='category__title'):
category_posts = Post.objects.all()
paginator = Paginator(category_posts, 5)
# We don't need to handle the case where the `page` parameter
# is not an integer because our URL only accepts integers
try:
category_posts = paginator.page('cats')
except EmptyPage:
# if we exceed the page limit we return the last page
category_posts = paginator.page(paginator.num_pages)
return render(request, 'categories.html', {'category_posts': category_posts})
urls.py:
path('category/<str:cats>/', views.CategoryView, name ="category"),
categories.html
{% extends 'base.html' %}
{%block content%}
<h1> Category: {{ cats }} </h1>
{% for post in category_posts %}
<div class="container mt-3">
<div class="row mb-2">
<div class="col-md-6">
<div class="card flex-md-row mb-4 box-shadow h-md-250">
<div class="card-body d-flex flex-column align-items-start">
<strong class="d-inline-block mb-2 text-primary">{{ post.category }}</strong>
<h3 class="mb-0">
<a class="text-dark" href="{% url 'detail' post.id %}">{{post.title}}</a>
</h3>
<div class="mb-1 text-muted">{{ post.public_date }}</div>
<p class="card-text mb-auto">{{ post.summary }}</p>
Continue reading
</div>
<img class="card-img-right flex-auto d-none d-md-block" data-src="holder.js/200x250?theme=thumb" alt="Thumbnail [200x250]" style="width: 200px; height: 250px;" src="data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22200%22%20height%3D%22250%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20200%20250%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_182c981dfc3%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A13pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_182c981dfc3%22%3E%3Crect%20width%3D%22200%22%20height%3D%22250%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2256.20000076293945%22%20y%3D%22131%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E" data-holder-rendered="true">
</div>
</div>
</div>
</div>
{% endfor %}
{% include 'pagination.html' %}
{%endblock%}
pagination.html
<div class="container mt-3">
<nav aria-label="Page navigation example">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item"><a class="page-link" href="/?page=1">First</a></li>
<li class="page-item"><a class="page-link" href="/?page={{ page_obj.previous_page_number }}">Previous</a></li>
{% endif %}
<li class="page-item"><a class="current" href="/?page={{ page_obj.number }} of {{ page_obj.paginator.num_pages }}">1</a></li>
{% if page_obj.has_next %}
<li class="page-item"><a class="page-link" href="/?page={{ page_obj.next_page_number }}">Next</a></li>
<li class="page-item"><a class="page-link" href="/?page={{lastpage}}">Last</a></li>
{% endif %}
</div>
I am very confused already in category views function to use parameter issue. so that I didn't use that code in pagination.html.
===== in view.py ======
from django.core.paginator import Paginator
def HomeView(request):
show_data = VehicleModel.objects.all() # Queryset For pagiantion
# Pagination code start
paginator = Paginator(show_data, 3, orphans=1)
page_number = request.GET.get('page')
show_data = paginator.get_page(page_number)
# Pagination code end
context = {'page_number':page_number}
return render(request,'dashboard.html',context)
===== in html file ======
<!-- Pagination Block with page number -->
<div class="container mt-5">
<div class="row float-right ">
<span class="m-0 p-0">
{% if carset.has_previous %} # <!-- For Previous Button -->
<a class="btn btn-outline-info" href="?page={{carset.previous_page_number}}&ok=#ok">Previous</a>
{% endif %}
<span>{% for pg in carset.paginator.page_range %} # <!-- For Page Numbers Buttons -->
{% if carset.number == pg %}
<a href="?page={{pg}}" class="btn btn-sm btn-primary">
<span class="badge">{{pg}}</span>
</a>
{% else %}
<a href="?page={{pg}}" class="btn btn-sm btn-secondary">
<span class="badge">{{pg}}</span>
</a>
{% endif %}
{% endfor %}</span>
{% if carset.has_next %} # <!-- For Next Button -->
<a class="btn btn-outline-info" href="?page={{carset.next_page_number}}&ok=#ok">Next</a>
{% endif %}
</span>
</div>
</div>
=========== Your code is like this ==============
here you passed the category parameter in the function so must pass the category title with the calling URL of this CategoryView(request, cats='category__title') function
def CategoryView(request, cats='category__title'):
category_posts = Post.objects.all()
paginator = Paginator(category_posts, 5)
with this CategoryView(request, cats='category__title') you want all Posts ???
def
CategoryView(request, cats='category__title'):
category_posts = Post.objects.filter(cats__title = cats)
paginator = Paginator(category_posts, 5)
ator = Paginator(category_posts, 5)
How do i get the name of the search item display in url. As shown in the image. For example i search for bag, i want the word 'bag' to be displayed in url.
def search_result(request):
query = request.GET.get('q', '')
if query is None:
return redirect("shop:homepage")
else:
item = Item.objects.all().order_by("timestamp")
if item:
item = item.filter(
Q(title__icontains=query)
).distinct()
if item.count() == 0:
messages.error(request, "No search results found")
paginator = Paginator(item, 1)
page = request.GET.get('page')
try:
queryset = paginator.page(page)
except PageNotAnInteger:
queryset = paginator.page(1)
except EmptyPage:
queryset = paginator.page(paginator.num_pages)
context = {
'search': queryset,
'query': query,
}
return render(request, 'search_result.html', context)
Add these lines into your view:
def search_result(request):
query = request.GET.get('q', '')
if query is None:
return redirect("shop:homepage")
else:
item = Item.objects.all().order_by("timestamp")
if item:
item = item.filter(Q(title__icontains=query)).distinct()
if item.count() == 0:
messages.error(request, "No search results found")
paginator = Paginator(item, 1)
page = request.GET.get('page')
try:
object_list = paginator.page(page)
except PageNotAnInteger:
object_list = paginator.page(1)
except EmptyPage:
object_list = paginator.page(paginator.num_pages)
queries_without_page = request.GET.copy()
if 'page' in queries_without_page:
del queries_without_page['page']
context = {
'search': queryset,
'object_list': object_list,
'queries': queries_without_page
}
return render(request, 'search_result.html', context)
and here is a complete pagination for function based views:
{% if object_list.has_other_pages %}
<ul>
{% if object_list.has_previous %}
<li>
<a role="button" href="?{{ queries.urlencode }}&page={{ object_list.previous_page_number }}"><span class="fa fa-angle-double-left"></span></a>
</li>
{% else %}
<li class="disabled">
<span role="button"><span class="fa fa-angle-double-left"></span></span>
</li>
{% endif %}
{% for i in object_list.paginator.page_range %}
{% if object_list.number == i %}
<li class="active">
<span role="button" class="mb-1 mt-1 mr-1 btn btn-sm btn-primary active pagination-btn">{{ i }} <span class="sr-only">(current)</span></span>
</li>
{% elif i > object_list.number|add:'-4' and i < object_list.number|add:'4' %}
<li>
<a role="button" href="?{{ queries.urlencode }}&page={{ i }}">{{ i }}</a>
</li>
{% endif %}
{% endfor %}
{% if object_list.has_next %}
<li>
<a role="button" href="?{{ queries.urlencode }}&page={{ object_list.next_page_number }}"><span class="fa fa-angle-double-right"></span></a>
</li>
{% else %}
<li class="disabled">
<span role="button"><span class="fa fa-angle-double-right"></span></span>
</li>
{% endif %}
</ul>
{% endif %}
I've followed the official docs to use paginator in Django and it not working, it shows the right page count but on every page, the whole list displayed instead of slicing it into many pages
views.py
def home(request):
current_user = request.user
all_dress = Item.objects.all().filter(dress_active=True).order_by('-created_at')
all_good = Item.objects.all().filter(dress_special=True)
all_name = Name.objects.all()
all_ads = Ads.objects.all()
#pig
paginator = Paginator(all_dress, 3) # Show 12 dress per page
page = request.GET.get('page')
dresss = paginator.get_page(page)
context = {
'all_dress': all_dress,
'all_name': all_name,
'current_user': current_user,
'all_good':all_good,
'all_ads':all_ads,
'dresss':dresss,
}
return render(request, 'fostan/index.html',context)
HTML
<div class="row">
<div class="col">
</div>
<div class="col">
<div dir="ltr">
<div class="pagination" align="left">
<span class="step-links" align="left">
{% if dresss.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page number {{ dresss.number }} of {{ dresss.paginator.num_pages }}
</span>
<br>
{% if dresss.has_next %}
next
last »
{% endif %}
</span>
</div>
</div>
</div>
<div class="col">
</div>
</div>
I have 9 items, and I asked the paginator to show only 3 items per page, the result is 3 pages with the same 9 items on every page!
item list
<ul class="thumbnails" >
{% for dress in all_dress %}
<li class="span4 pull-left" >
<div class="thumbnail">
<a class="zoomTool" href="{% url 'dress_details' dress.pk%}" title="add to cart"><span class="icon-search"></span> عرض التفاصيل</a>
<img class="main" src="{{ dress.dress_image1.url }}" alt="">
<div class="caption">
<h5> فستان {{ dress.dress_name }} </h5>
<h4>
<a class="defaultBtn" href="{% url 'dress_details' dress.pk%}" title="إضفط لمشاهدة الفستان"><span class="icon-zoom-in"></span></a>
<span class="pull-left">{{ dress.dress_price }} جنيه </span>
</h4>
</div>
</div>
</li>
{% endfor %}
</ul>
You should do this way:
paginator = Paginator(all_dress, 3)
page = request.GET.get('page')
try:
dresss = paginator.page(page)
except PageNotAnInteger:
dresss = paginator.page(1)
except EmptyPage:
dresss = paginator.page(paginator.num_pages)
I'm trying to understand some source code which is used in a ListView to generate pagination links at the bottom of the page. For example, on a page listing 'experts', it looks like this:
It seems to be implemented somewhat differently from the way described in https://docs.djangoproject.com/en/2.0/topics/pagination/. There is an inclusion tag called paginator:
from django import template
from django.core.paginator import EmptyPage
from dashboard.views.utils import query_dict_from_params_or_cookies
register = template.Library()
def query_params(params):
query = params.copy()
if query.get('page'):
del query['page']
return '&' + query.urlencode() if query.urlencode() else ''
#register.inclusion_tag('templatetags/paginator.html', takes_context=True)
def paginator(context, adjacent_pages=2):
request = context['request']
page_obj = context['page_obj']
page_range = context['paginator'].page_range
page_number = page_obj.number
last_page_number = len(page_range)
left_idx = max(0, page_number - adjacent_pages - 1)
right_idx = min(page_number + adjacent_pages, last_page_number)
if left_idx == 2:
left_idx -= 1
if right_idx == last_page_number - 2:
right_idx += 1
window = page_range[left_idx:right_idx]
try:
previous_page_number = page_obj.previous_page_number()
except EmptyPage:
previous_page_number = None
try:
next_page_number = page_obj.next_page_number()
except EmptyPage:
next_page_number = None
params = query_dict_from_params_or_cookies(request)
return {
'has_previous': page_obj.has_previous(),
'has_next': page_obj.has_next(),
'previous_page_number': previous_page_number,
'next_page_number': next_page_number,
'last_page_number': last_page_number,
'page_range': window,
'page_number': page_number,
'show_first': page_number > adjacent_pages + 1,
'show_left_gap': page_number > adjacent_pages + 3,
'show_last': page_number < last_page_number - adjacent_pages,
'show_right_gap': page_number < last_page_number - adjacent_pages - 2,
'query_params': query_params(params)
}
The corresponding template, templatetags/paginator.html, looks like this:
<ul class="pagination right"
{% if has_previous %}data-previous-page="?page={{ previous_page_number }}{{ query_params }}"{% endif %}
{% if has_next %}data-next-page="?page={{ next_page_number }}{{ query_params }}"{% endif %}>
{% if has_previous %}
<li class="waves-effect">
<a href="?page={{ previous_page_number }}{{ query_params }}">
<i class="material-icons">chevron_left</i>
</a>
</li>
{% else %}
<li class="disabled">
<a><i class="material-icons">chevron_left</i></a>
</li>
{% endif %}
{% if show_first %}
<li>1</li>
{% endif %}
{% if show_left_gap %}
<li class="disabled"><a>...</a></li>
{% endif %}
{% for i in page_range %}
{% if page_number == i %}
<li class="active"><a>{{ i }}</a></li>
{% else %}
<li class="waves-effect">{{ i }}</li>
{% endif %}
{% endfor %}
{% if show_right_gap %}
<li class="disabled"><a>...</a></li>
{% endif %}
{% if show_last %}
<li>
{{ last_page_number }}
</li>
{% endif %}
{% if has_next %}
<li class="waves-effect">
<a href="?page={{ next_page_number }}{{ query_params }}">
<i class="material-icons">chevron_right</i>
</a>
</li>
{% else %}
<li class="disabled">
<a><i class="material-icons">chevron_right</i></a>
</li>
{% endif %}
</ul>
What I don't quite understand is how paginator and page_obj get inserted into the template's context. For example, I did a project-wide search for page_obj and it does not appear that it is being injected in our own code, which would mean that it is being injected by Django's source code. But how is this being done?
Also, it seems to me like some of the logic essentially replicates what is in Django's Paginator class and this code could be simplified/refactored, would anyone agree?
It would appear that this is indeed done by Django's source code - specifically, by the generic ListView. The get_context_data() method of the MultipleObjectMixin (from which ListView inherits) reads:
def get_context_data(self, *, object_list=None, **kwargs):
"""Get the context for this view."""
queryset = object_list if object_list is not None else self.object_list
page_size = self.get_paginate_by(queryset)
context_object_name = self.get_context_object_name(queryset)
if page_size:
paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, page_size)
context = {
'paginator': paginator,
'page_obj': page,
'is_paginated': is_paginated,
'object_list': queryset
}
else:
context = {
'paginator': None,
'page_obj': None,
'is_paginated': False,
'object_list': queryset
}
if context_object_name is not None:
context[context_object_name] = queryset
context.update(kwargs)
return super().get_context_data(**context)
Clearly, paginator and page_obj are added to the context here.