I am setting up a pagination in my Django APP. Following is my view code:
class ClaimsView(ListView):
context_object_name = "archives"
template_name = "myapp/claims.html"
def get_queryset(self, **kwargs):
query = self.request.GET.get("q", "")
response = self.get_archives(query)
paginator =Paginator(response, 4)
pages = paginator.get_pages(4)
return {'archives': response, 'pages': pages}
When I print pages in the viwes file. It give correct result "<page 1 of 1>"
but when I am passing it to the HTML file its not give any results there.
'archives' in above dict has a list as value its working fine but not the 'pages'
This is how I am reading it in HTML file:
{{pages}}
get queryset method should always return a list or queryset not a dictionary. for pagination...in get of your listview do something like this
def get(self, *args, **kwargs):
context = {}
response = "your queryset"
paginator_obj=Paginator(response,4)
page_number=self.request.GET.get('page',1)
students=paginator_obj.get_page(page_number)
context["page_obj"] = paginator_obj
if self.request.get_full_path().endswith('/'):
fullpath = self.request.get_full_path()+'?page='
else:
fullpath = self.request.get_full_path()
context['fullpath'] = fullpath
context['object_list'] = response
return render(self.request, self.template_name, context)
in your template do something like this
<div class="text-center">
{% if object_list.has_other_pages %}
<ul class="pagination" style="text-align:center; width:100% ;justify-content: center!important;">
{% if object_list.has_previous %}
<li class="page-item"><a class="page-link" href="{{ fullpath }}&page={{ page_obj.previous_page_number }}">«</a></li>
{% else %}
<li class="page-item" class="disabled"><span class="page-link">«</span></li>
{% endif %}
{% for i in object_list.paginator.page_range %}
{% if object_list.number == i %}
<li class="page-item"class="active"><span class="page-link">{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li class="page-item"><a class="page-link" href="{{ fullpath }}&page={{ i }}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if object_list.has_next %}
<li class="page-item"><a class="page-link" href="{{ fullpath }}&page={{ page_obj.next_page_number }}">»</a></li>
{% else %}
<li class="page-item" class="disabled"><span class="page-link">»</span></li>
{% endif %}
</ul>
{% endif %}
</div>
Related
views.py
import datetime
from .filters import MyModelFilter
from django.shortcuts import render
import pymysql
from django.http import HttpResponseRedirect
from facligoapp.models import Scrapper
from django.db.models import Q
from django.utils import timezone
import pytz
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
users = ""
def index(request):
if request.method == "POST":
from_date = request.POST.get("from_date")
f_date = datetime.datetime.strptime(from_date,'%Y-%m-%d')
print(f_date)
to_date = request.POST.get("to_date")
t_date = datetime.datetime.strptime(to_date, '%Y-%m-%d')
print(t_date)
get_records_by_date = Scrapper.objects.all().filter(Q(start_time__date=f_date)|Q(end_time__date=t_date))
print(get_records_by_date)
filtered_dates = MyModelFilter(request.GET,queryset=get_records_by_date)
page = request.GET.get('page', 1)
paginator = Paginator(filtered_dates.qs, 5)
global users
try:
users = paginator.get_page(page)
except PageNotAnInteger:
users = paginator.page(1)
except EmptyPage:
users = paginator.page(paginator.num_pages)
else:
roles = Scrapper.objects.all()
page = request.GET.get('page', 1)
paginator = Paginator(roles, 5)
try:
users = paginator.page(page)
except PageNotAnInteger:
users = paginator.page(1)
except EmptyPage:
users = paginator.page(paginator.num_pages)
return render(request, "home.html", {"users": users})
return render(request, "home.html", {"users": users})
filters.py:
import django_filters
from.models import Scrapper
class MyModelFilter(django_filters.FilterSet):
class Meta:
model = Scrapper
# Declare all your model fields by which you will filter
# your queryset here:
fields = ['start_time', 'end_time']
home.html
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<body>
<style>
h2 {text-align: center;}
</style>
<h1>Facilgo Completed Jobs</h1>
<form action="" method="post">
{% csrf_token %}
<label for="from_date">From Date:</label>
<input type="date" id="from_date" name="from_date">
<label for="to_date">To Date:</label>
<input type="date" id="to_date" name="to_date">
<input type="submit"><br>
</form>
<div class="container">
<div class="row">
<div class="col-md-12">
<h2>Summary Details</h2>
<table id="bootstrapdatatable" class="table table-striped table-bordered" width="100%">
<thead>
<tr>
<th>scrapper_id</th>
<th>scrapper_jobs_log_id</th>
<th>external_job_source_id</th>
<th>start_time</th>
<th>end_time</th>
<th>scrapper_status</th>
<th>processed_records</th>
<th>new_records</th>
<th>skipped_records</th>
<th>error_records</th>
</tr>
</thead>
<tbody>
{% for stud in users %}
{% csrf_token %}
<tr>
<td>{{stud.scrapper_id}}</td>
<td>{{stud.scrapper_jobs_log_id}}</td>
<td>{{stud.external_job_source_id}}</td>
<td>{{stud.start_time}}</td>
<td>{{stud.end_time}}</td>
<td>{{stud.scrapper_status}}</td>
<td>{{stud.processed_records}}</td>
<td>{{stud.new_records}}</td>
<td>{{stud.skipped_records}}</td>
<td>{{stud.error_records}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if users.has_other_pages %}
<ul class="pagination">
{% if users.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% if user.number|add:'-4' > 1 %}
<li>…</li>
{% endif %}
{% for i in users.paginator.page_range %}
{% if users.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% elif i > users.number|add:'-5' and i < users.number|add:'5' %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if users.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
</div>
</div>
</div>
</body>
</html>
I need to get only the datas which I have filtered et_records_by_date = Scrapper.objects.all().filter(Q(start_time__date=f_date)|Q(end_time__date=t_date)) in pagination. But when I click the next page its showing different datas. Is there any solution to get only the datas for the particular query. When I post the datas the of dates the 1st pages is showing the correct details but when I click page 2 its showing the other datas
When you click on 'next page' you're performing a GET request, and not a POST request. Which means it will go into the else block, which has no filtering but just returns all the Scrapper objects.
You're better off including the from_date and to_date in a GET request and not using a POST request.
If you're using a form you can simply set the method:
<form method="GET" action="..." />
Shared method
def paginate(request,obj,total=25):
paginator = Paginator(obj,total)
try:
page = int(request.GET.get('page', 1))
except:
page = 1
try:
obj_list = paginator.page(page)
except(EmptyPage,InvalidPage):
obj_list = paginator.page(paginator.num_pages)
return obj_list
View
users = UserInfo.objects.all()
data = {
'users': paginate(request,users,15),
}
return render(request,self.template_name,data)
HTML
{% include './pagination.html' with obj=users %}
pagination.html file
{% if obj.paginator.num_pages > 1 %}
<div class="text-center">
<ul class="pagination">
<li class="{% if not obj.has_previous %} disabled{% endif %}">
{% if obj.has_previous %}
<a data-page="{{obj.previous_page_number}}" href="?page={{obj.previous_page_number}}{% for key, value in request.GET.items %}{% if key != 'page' %}&{{ key }}={{ value }}{% endif %}{% endfor %}" aria-label="{% trans 'Previous' %}" tabindex="-1"> « </a>
{% else %}
<a data-page="0" class="" href="javascript:void(0);" tabindex="-1">«</a>
{% endif %}
</li>
{% for i in obj.paginator.page_range %}
{% if obj.number == i %}
<li class="active">
<a data-page="0" class="" href="javascript:void(0)">{{ i }}</a>
</li>
{% elif i > obj.number|add:'-5' and i < obj.number|add:'5' %}
<li class=""><a data-page="{{i}}" class="" href="?page={{i}}{% for key, value in request.GET.items %}{% if key != 'page' %}&{{ key }}={{ value }}{% endif %}{% endfor %}">{{ i }}</a>
</li>
{% endif %}
{% endfor %}
<li class="{% if not obj.has_next %} disabled{% endif %}">
{% if obj.has_next %}
<a data-page="{{ obj.next_page_number }}" class="" href="?page={{obj.next_page_number}}{% for key, value in request.GET.items %}{% if key != 'page' %}&{{ key }}={{ value }}{% endif %}{% endfor %}" tabindex="-1">»</a>
{% else %}
<a data-page="0" class="" href="javascript:void(0);" tabindex="-1">»</a>
{% endif %}
</li>
</ul>
</div>
{% endif %}
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 }}
urls.py
urlpatterns = [
path('',CourseList.as_view(),name='course_list'),
path('create/',CourseCreate.as_view(),name='course_create'),
path('<int:cid>/',CourseView.as_view(),name='course_view'),
]
views.py
COURSE_PERM_GUEST = 0
COURSE_PERM_STUDENT = 1
COURSE_PERM_TEACHER = 2
COURSE_PERM_MEMBER = 3
class CourseAccessMixin(AccessMixin):
permission = None
extra_context = {}
def dispatch(self,request,*args,**kwargs):
if not request.user.is_authenticated:
return super().handle_no_permission()
self.course = get_object_or_404(Course,id=kwargs['cid'])
user_perm = COURSE_PERM_GUEST
if self.course.teacher == request.user:
user_perm = COURSE_PERM_TEACHER
elif self.course.enroll_set.filter(student=request.user).exists():
user_perm = COURSE_PERM_STUDENT
if not request.user.is_superuser and self.permission is not None:
is_accessible = False
if self.permission == COURSE_PERM_GUEST and \
user_perm == COURSE_PERM_GUEST:
is_accessible = True
elif (self.permission & user_perm) != 0:
is_accessible = True
if not is_accessible:
return super().handle_no_permission()
self.extra_context.update({'course':self.course})
return super().dispatch(request,*args,**kwargs)
class CourseView(CourseAccessMixin,DetailView):
extra_context = {'title':'檢視課程'}
model = Course
pk_url_kwarg = 'cid'
models.py
class Course(models.Model):
name = models.CharField('課程名稱',max_length=50)
enroll_password = models.CharField('選課密碼',max_length=50)
teacher = models.ForeignKey(User,models.CASCADE)
def __str__(self):
return '{}#{} ({})'.format(
self.id,
self.name,
self.teacher.first_name)
course_list.html
{% extends "base.html" %}
{% load user_tags %}
{% block content %}
{% if user|is_teacher %}
<div class="mb-2">
建立課程
</div>
{% endif %}
<div id="course_list">
{% for course in course_list %}
<div class="list-group">
<div class="list-group-item d-flex">
{% if user.is_authenticated %}
{{ course.name }}
{% else %}
{{ course.name }}
{% endif %}
<small class="ml-auto">{{ course.teacher.first_name }} 老師</small>
</div>
</div>
{% endfor %}
</div>
{% include 'pagination.html' %}
{% endblock %}
course_detail.html
{% extends 'base.html' %}
{% load user_tags %}
{% block content %}
<div id="course_view" class="card">
{% with b1 = "btn btn-sm btn-primary" b2 = "btn btn-sm btn-secondary" %}
<div class="card-header d-flex">
<div>
{{ course.name }}
<small>{{ course.teacher.first_name }} 老師</small>
</div>
{% if user.is_superuser or course.teacher == user %}
<div class="ml-auto">
<span class="badge badge-light">
選課密碼: {{ course.enroll_password }}
</span>
<a href="{% url 'course_edit' course.id %}" class="{{ b1 }}">
<i class="fas fa-edit"></i>編輯
</a>
</div>
{% endif %}
</div>
<div class="card-body">
{% block course_detail_body %}
<div id="student_op" class="btn-group">
{% if not course|has_member:user and not user.is_superuser %}
<a href="{% url 'course_enroll' course.id %}" class="{{ b1 }}">
<i class="fas fa-id-badge"></i>選修
</a>
{% else %}
<a href="{% url 'course_users' course.id %}" class="{{ b1 }}">
<i class="fas fa-users"></i>修課名單
</a>
{% if course|has_student:user %}
<a href="{% url 'course_seat' course.id %}" class="{{ b1 }}">
<i class="fas fa-chair"></i>更改座號
</a>
{% endif %}
{% endif %}
</div>
{% endblock %}
</div>
{% endwith %}
</div>
{% endblock %}
Error:
ValueError at /course/1/
The view course.views.CourseView didn't return an HttpResponse object. It returned None instead.
I had a view CourseView and when I try to access the detail of the corresponding course by clicking the hyperlink {{ course.name }} from the template course_list.html, I received the error message showing that it didn't return an HttpResponse object. I do not know what is missing in order to have the details accessible even though I had set the pk_url_kwarg?
You forget to add return super().dispatch(request,*args,**kwargs) and the end of dispatch function (you add it, only in if condition)
change this
self.extra_context.update({'course':self.course})
return super().dispatch(request,*args,**kwargs)
To this:
self.extra_context.update({'course':self.course})
return super().dispatch(request,*args,**kwargs)
return super().dispatch(request,*args,**kwargs)
i want to display an image if nothing could be found trough my searchg function.
I setup 2 serach functions. one for elasticsearch and the other one for a local search query view, anyways the one for elastic does not seems to work or at least it does not display the "not found" image if the object_list is empty, any idea?
elastic_search_function:
def globalsearch_elastic(request):
qs = request.GET.get('qs')
page = request.GET.get('page')
if qs:
qs = PostDocument.search().query("multi_match", query=qs, fields=["title", "content", "tag"])
qs = qs.to_queryset()
else:
qs = ''
paginator = Paginator(qs, 10) # Show 10 results per page
try:
qs = paginator.page(page)
except PageNotAnInteger:
qs = paginator.page(1)
except EmptyPage:
qs = paginator.page(paginator.num_pages)
return render(request, 'myproject/search/search_results_elastic.html', {'object_list':qs})
template.html
<body>
<h1 class="center">Search results <a class="fa fa-search"></a></h1>
<hr class="hr-style">
{% if object_list.count == 0 %}
<div class="search_not_found">
<img src={% static "/gfx/sys/not_found.png" %}>
<h2>Nothing found here ...</h2>
</div>
{% else %}
{% for post in object_list %}
<div class="post">
<h3><u>{{ post.title }}</u></h3>
<p>{{ post.content|safe|slice:":800"|linebreaksbr}}
{% if post.content|length > 300 %}
... more
{% endif %}</p>
<div class="date">
<a>Published by: <a href="{% url 'profile' pk=user.pk %}" >{{ post.author }}</a></a><br>
<a>Published at: {{ post.published_date }}</a><br>
<a>Category: {{ post.category }}</a><br>
<a>Tag(s): {{ post.tag }}</a><br>
<a>Comment(s): {{ post.comment_set.count }}</a>
</div>
</div>
{% endfor %}
{% endif %}
How about like this using empty:
{% for post in object_list %}
<div class="post">
<h3><u>{{ post.title }}</u></h3>
<p>{{ post.content|safe|slice:":800"|linebreaksbr}}
{% if post.content|length > 300 %}
... more
{% endif %}</p>
<div class="date">
<a>Published by: <a href="{% url 'profile' pk=user.pk %}" >{{ post.author }}</a></a><br>
<a>Published at: {{ post.published_date }}</a><br>
<a>Category: {{ post.category }}</a><br>
<a>Tag(s): {{ post.tag }}</a><br>
<a>Comment(s): {{ post.comment_set.count }}</a>
</div>
</div>
{% empty %}
<div class="search_not_found">
<img src={% static "/gfx/sys/not_found.png" %}>
<h2>Nothing found here ...</h2>
</div>
{% endfor %}
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.