Pagination Elasticsearch in Django - django

I am a newbie in Elasticsearch, I just try to create a search engine using it in Django. Overall, the engine shows good results. Unfortunately, it loads a large number of the results. Then, I try to paginate it by regular pagination in Django, after that, the page load error object of type 'Search' has no len().
These are my codes:
view.py
from django.shortcuts import render, redirect
from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search
from django.core.paginator import Paginator
def search_es(request):
return render(request,'search/search.html')
def results(request):
s = Search(using=Elasticsearch())
keyword = request.GET.get('q') # keyword that want to be found
print(keyword)
if keyword:
# posts = s.query('match_phrase_prefix',head_title=keyword)
# if posts.count() == 0:
posts = s.query(
"multi_match",
query=keyword,
fields=['head_title^5', 'description^5', 'description.ngram'],
# type="phrase_prefix",
)
posts = posts[0: 100]
else:
posts = ''
page = request.GET.get('page', 1)
paginator = Paginator(posts, 10)
try:
users = paginator.page(page)
except PageNotAnInteger:
users = paginator.page(1)
except EmptyPage:
users = paginator.page(paginator.num_pages)
context = {
'page_title': keyword,
'posts': users,
'count': posts.count(),
'keyword': keyword,
}
return render(request,'search/results.html',context)
results.html
{% if posts.has_other_pages %}
<ul class="pagination">
{% if posts.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in posts.paginator.page_range %}
{% if posts.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if posts.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
Hope for every possible solution.
Thank you very much.

ElasticSearch provided two parameters you can use for pagination: from and size. You can refer to https://elasticsearch-dsl.readthedocs.io/en/latest/search_dsl.html#pagination
for example:
posts = s[0:20].query(
"multi_match",
query=keyword,
fields=['head_title^5', 'description^5', 'description.ngram'],
# type="phrase_prefix",
)
to get first page, and page size is 20.

Related

I don't know why my page isn't paginating i don't get any errors pls help :)

The page is supposed to get paginated but it doesn't I don't know what I did wrong. If anyone can help me figure it out i will appreciate
This is for a comment section on a site and I don't really know how to fix it. I've been looking the problem up on the web with no results then came here
from django.core.paginator import Paginator
def Home_view(request):
posts = Post.objects.order_by("-date_posted")
all_experiences = Experience.objects.order_by("-id")
all_educations = Education.objects.order_by("-id")
all_skills = Skill.objects.all()
paginator = Paginator(posts, 1)
page = request.GET.get('page')
post_list = paginator.get_page(page)
context = {
'posts': posts,
'all_experiences': all_experiences,
'all_educations': all_educations,
'all_skills': all_skills,
}
return render(request, 'resume.html', context)
Html Page supposed to get paginated
{% if is_paginated %}
<div class="pagination">
<span class="step-links">
{% if post_list.has_previous %}
« first
<a href="?page={{ post_list.previous_page_number }}">previous
</a>
{% endif %}
<span class="current">
Page{{post_list.number}}of{{post_list.paginator.num_pages}}.
</span>
{% if post_list.has_next %}
next
<a href="?page={{ post_list.paginator.num_pages }}">last»
</a>
{% endif %}
</span>
</div>
{% endif %}
{% else %}
the page is supposed to show 5 posts at once but doesn't and doesn't throw out any errors it just doesn't work
It looks like you aren't adding post_list to your context so {% if post_list.has_previous %} does nothing. You are passing posts which is the unpaginated list of posts. You will also need to add is_paginated to the context. Try updating context to something like:
context = {
'all_experiences': all_experiences,
'all_educations': all_educations,
'all_skills': all_skills,
'post_list': post_list,
'is_paginated': True,
}

How to get paginated answer's response?

I am using django as backend for website
There will be 10 qwestions
i want to paginate them (one qwestion's ans is given then go to next so on ) and atlast give marks calculated based on all the answers given
Any hints on how to do it?
I found somthing similar but dont know how to implement in django
What's the most efficient way to calculate a running total/balance when using pagination (PHP, MySQL)
Have you looked to Django Pagination docs?
https://docs.djangoproject.com/en/2.1/topics/pagination/
From that page
Your view:
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.shortcuts import render
def listing(request):
contact_list = Contacts.objects.all()
paginator = Paginator(contact_list, 25) # 25 is the items per page, in Your case would be 1
page = request.GET.get('page')
contacts = paginator.get_page(page)
return render(request, 'list.html', {'contacts': contacts})
Your template:
{% for contact in contacts %}
{# Each "contact" is a Contact model object. #}
{{ contact.full_name|upper }}<br>
...
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if contacts.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
</span>
{% if contacts.has_next %}
next
last »
{% endif %}
</span>
</div>
To go to a page you should add to the url ?page=1 where 1 is the page number.

Django pagination - 5k objects

As a continuation of this question Django pagination with bootstrap any my works under my Contacts app I have to ask for your help once more. I have a problem I cannot resolve. I used few suggestions about pagination but all that is changing is the bottom pagination menu. My app is still loading all 5k objects every time, over and over. I am new at this, this app is my first project and this is the final 'big' missing part. I promiss to post final cone when I'm done :)
Best regards.
views.py
def index(request):
contacts_list = contacts.objects.all()
contacts_filter = LFilter(request.GET, queryset=contacts_list)
paginator = Paginator(contacts_list, 50)
try:
page = int(request.GET.get('page','1'))
except:
page = 1
try:
contacts = paginator.page(page)
except PageNotAnInteger:
contacts = paginator.page(1)
except EmptyPage:
contacts = paginator.page(paginator.num_pages)
index = contacts.number - 1
max_index = len(paginator.page_range)
start_index = index - 3 if index >= 3 else 0
end_index = index + 3 if index <= max_index - 3 else max_index
page_range = paginator.page_range[start_index:end_index]
return render(
request, 'index.html',
context={'filter': contacts_filter,
'contacts': contacts,
'page_range': page_range, }
)`
index.py
{% for obj in filter.qs %}
Code for contact information to display
{% endfor %}
<div class="prev_next">
{% if contacts.has_previous %}
<a class="prev btn btn-info" href="?page={{contacts.previous_page_number}}">Prev</a>
{% endif %}
{% if contacts.has_next %}
<a class="next btn btn-info" href="?page={{contacts.next_page_number}}">Next</a>
{% endif %}
<div class="pages">
<ul>
{% for pg in page_range %}
{% if contacts.number == pg %}
<li>{{pg}}</li>
{% else %}
<li>{{pg}}</li>
{% endif %}
{% endfor %}
</ul>
</div>
<span class="clear_both"></span>
</div>

django paginator page numbers not working with if

I have the following template based pagination:
{% for ipage in transactions.paginator.page_range %}
<li {% if ipage == page %} class="active"{%endif%}>{{ipage}} - {{page}}</li>
{% endfor %}
The view page looks like this:
trans_list = Transaction.objects.all()
paginator = Paginator(trans_list, 15)
page = request.GET.get('page')
try:
transactions = paginator.page(page)
except PageNotAnInteger:
transactions = paginator.page(1)
except EmptyPage:
transactions = paginator.page(paginator.num_pages)
context = {
'page':page,
'transactions':transactions,
}
ipage and page both print the page number, but the if doesn't display the active class when they match in the for loop.
How can I get the if to match when the page number and the for loop index match?
That should do the trick.
{% for ipage in transactions.paginator.page_range %}
{% ifequal ipage transactions.number %}
<!-- Do something special for this page -->
{% else %}
<!-- All the other pages -->
{% endifequal %}
{% endfor %}

How to create pagination in Django?

I follow this Document of djangoproject.com : https://docs.djangoproject.com/en/1.8/topics/pagination/. But it is too simple. It is only Next and Previous button.
Now I want create pagination with more features such as http://i.imgur.com/ZiFeAqG.jpg.
This is code:
View.py
def hire(request):
hire_article_list = hire_article.objects.all().order_by('-id')
#hire_article_list = hire_article.objects.order_by("-publication_date")
paginator = Paginator(hire_article_list, 2) # Show 25 contacts per page
page = request.GET.get('page')
try:
hire_article_s = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
hire_article_s = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
hire_article_s = paginator.page(paginator.num_pages)
#return render_to_response('hire/list.html', {"page_list": page_list})
context = {'hire_article_s': hire_article_s}
return render(request, 'hire/list.html', context)
list.html
{% for j in hire_article_s %}
{# Each "j" is a page_list model object. #}
<li>{{ j.hiring}}</li>
{% endfor %}
{% if hire_article_s.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ hire_article_s.number }} of {{ hire_article_s.paginator.num_pages }}.
</span>
{% if hire_article_s.has_next %}
next
{% endif %}
</span>
</div>
I had a similar need last week and found this super useful gist (https://gist.github.com/jsatt/8183993) that worked fine (though I'm not sure why it wouldn't work till I put request in the function parameters). It's a subclass of django's Paginator function. You could put this in a utility file and call it whenever you want to use Paginate with the range.
For instance, I had mine in a file called utils.py, which is in my core app.
views.py
from core.utils import paginate
def hire(request):
hire_article_list = hire_article.objects.all().order_by('-id')
'''
Show 25 contacts per page, with a page range of 5, which means if you are
on page 8, it shows links to pages 6,7,8,9,10.
'''
hire_article_s = paginate(request, hire_article_list, 25, 5)
context = {'hire_article_s': hire_article_s}
return render(request, 'hire/list.html', context)
list.html
{% if hire_article_s.has_previous %}
previous
{% endif %}
{% for range in hire_article_s.neighbor_range %}
{% if range == hire_article_s.number %}
<li class="pagination__item active ">{{ range }}</li>
{% else %}
<li class="{% if range == hire_article_s.number %}active {% endif %}">{{ range }}</li>
{% endif %}
{% endfor %}
{% if hire_article_s.has_next %}
next
{% endif %}
Hope this helps.
UPDATE
The above code has been edited a bit. I've added the context and the template format. Note that I'm using a loop to go through {{ hire_article_s.neighbor_range }} and print out the page numbers. I also do a check to highlight the current page's number. the This should work, as it's pretty much my own code with your own variable names.