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 %}
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 %}
views.py
def do_paginator(get_records_by_date,request):
page = request.GET.get('page', 1)
paginator = Paginator(get_records_by_date, 5)
try:
users = paginator.page(page)
except PageNotAnInteger:
users = paginator.page(1)
except EmptyPage:
users = paginator.page(paginator.num_pages)
return 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)
new_records_check_box_status = request.POST.get("new_records", None)
print(new_records_check_box_status)
error_records_check_box_status = request.POST.get("error_records", None)
print(error_records_check_box_status)
drop_down_status = request.POST.get("field",None)
print(drop_down_status)
global get_records_by_date
if new_records_check_box_status is None and error_records_check_box_status is None:
get_records_by_date = Scrapper.objects.filter(start_time__date__range=(f_date, t_date))
get_records_by_date = check_drop_down_status(get_records_by_date,drop_down_status)
get_records_by_date = do_paginator(get_records_by_date,request)
elif new_records_check_box_status and error_records_check_box_status is None:
get_records_by_date = Scrapper.objects.filter(start_time__date__range=(f_date, t_date)).filter(new_records__gt=0)
get_records_by_date = check_drop_down_status(get_records_by_date, drop_down_status)
get_records_by_date = do_paginator(get_records_by_date, request)
elif error_records_check_box_status and new_records_check_box_status is None:
get_records_by_date = Scrapper.objects.filter(start_time__date__range=(f_date, t_date)).filter(error_records__gt=0)
get_records_by_date = check_drop_down_status(get_records_by_date, drop_down_status)
get_records_by_date = do_paginator(get_records_by_date, request)
else:
get_records_by_date = Scrapper.objects.filter(start_time__date__range=(f_date, t_date)).filter(Q(new_records__gt=0)|Q(error_records__gt=0))
get_records_by_date = check_drop_down_status(get_records_by_date, drop_down_status)
get_records_by_date = do_paginator(get_records_by_date,request)
# print(get_records_by_date)
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": get_records_by_date})
home.html
<!DOCTYPE html>
<html>
<body>
<style>
h2 {text-align: center;}
</style>
<h1>Facilgo Completed Jobs</h1>
<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>
{% if stud.end_time == None %}
<td style="color:red">No result</td>
{% else %}
<td>{{stud.end_time}}</td>
{% endif %}
{% if stud.scrapper_status == "1" %}
<td>{{stud.scrapper_status}} --> Started</td>
{% else %}
<td>{{stud.scrapper_status}} --> Completed</td>
{% endif %}
<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>
When I filter the datas the first page is getting the correct details. But when I click the next page its going to different datas. For the filtered element the datas should be obtained from the filtered query set. How to paginate according to the filtered datas. The second page is mismatched and returning to the original total datas.
Is there any solution to paginate the datas which has been filtered.
You don't need the if else block, you can simply do as it is documented here.
page = request.GET.get('page')
paginator = Paginator(get_records_by_date, 5)
users = paginator.get_page(page)
return users
The django method already deals with input verification in the page GET, so you don't need to worry with the input you get.
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)
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.