How to use pagination after you query for results? - python

I'm trying to make a search functionality with 2 parameters. Everything works fine, until I want to use pagination.
I've been testing it by displaying only 1 element per page. This works, until I want to change the page.
When I change the page, I get no results even though I have entries that should be displayed in the DB.
Tbh I think that I should somehow store the search parameters and do the query when the page changes, but that makes no sense for me. How does pagination help if I still have to do the query everytime I change the page?
Views.py
def cautare(req):
intrari_oferte = Oferta.objects.get_queryset().distinct('denumireMeserie')
context = {
'title': "Cautare loc de munca | Best DAVNIC73",
'oferte': intrari_oferte
}
return render(req, "../templates/pagini/cautare-loc-de-munca.html", context)
def locuridemunca(req):
jud = req.POST.get('inputjudet')
meserie = req.POST.get('inputmeserie')
intrari_oferte = Oferta.objects.filter(judet=jud, denumireMeserie=meserie)
pagIntrari = Paginator(intrari_oferte, 1)
page = req.GET.get('page')
pagina = pagIntrari.get_page(page)
context = {
'title': "Cautare loc de munca | Best DAVNIC73",
'judet': jud,
'meserie': meserie,
'pagina': pagina
}
return render(req, "../templates/pagini/locuri-de-munca.html", context)
cautare template
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container container-centru">
<h1 class="heading-contact">Cauta loc de munca</h1>
<form class="form-contact" action="{% url 'locuridemunca' %}" method="POST">
{% csrf_token %}
<select name="inputjudet" class="selectare-judet-cautare" style="display: block;">
<option selected disabled>Selecteaza judetul!</option>
<optgroup label="Sud Muntenia">
<option value="Prahova">Prahova</option>
<option value="Dambovita">Dambovita</option>
<option value="Calarasi">Calarasi</option>
<option value="Arges">Arges</option>
<option value="Teleorman">Teleorman</option>
<option value="Giurgiu">Giurgiu</option>
<option value="Ialomita">Ialomita</option>
</optgroup>
<optgroup label="Centru">
<option value="Sibiu">Sibiu</option>
<option value="Alba">Alba</option>
<option value="Mures">Calarasi</option>
<option value="Covasna">Covasna</option>
<option value="Harghita">Harghita</option>
<option value="Brasov">Brasov</option>
</optgroup>
</select>
<select name="inputmeserie" class="selectare-meserie-cautare" style="display: block;">
<option selected disabled>Selecteaza meseria!</option>
{% for meserie in oferte %}
<option value="{{ meserie.denumireMeserie }}">{{ meserie.denumireMeserie }}</option>
{% endfor %}
</select>
<div class="form-group form-group-custom">
<input type="submit" value="Cauta!" class="btn btn-secondary btn-selectare-judet-cautare">
</div>
</form>
</div>
{% endblock %}
locuri de munca template
{% extends 'base.html' %}
{% load static %}
{% block content %}
<div class="container container-munca">
{% if pagina %}
<h1 class="heading-munca">Locuri de munca de {{meserie}} din judetul {{judet}}</h1>
<div class="row">
{% for oferta in pagina %}
<div class="col-md-4">
<div class="card card-custom">
<div class="card-body">
<h5 class="card-title">{{oferta.denumireMeserie}}</h5>
<h6 class="card-subtitle mb-2 text-muted">{{oferta.agentEconomic}}</h6>
<p class="card-text">{{oferta.adresa}}</p>
Card link
</div>
</div>
</div>
{% endfor %}
</div>
{% if pagina.has_other_pages %}
<div class="row">
<div class="col-md-12">
<ul class="pagination">
{% if pagina.has_previous %}
<li class="page-item">
«
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">«</a>
</li>
{% endif %}
<li class="page-item active">
<a class="page-link">1</a>
</li>
{% if pagina.has_next %}
<li class="page-item">
»
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">»</a>
</li>
{% endif %}
</ul>
</div>
</div>
{% endif %}
{% else %}
<div class="row">
<div class="col-md-12">
<div class="card card-custom">
<div class="card-body">
<h5 class="card-title" style="text-align: center;">Nu am putut gasi rezultate!</h5>
</div>
</div>
</div>
</div>
{% endif %}
</div>
{% endblock %}
cautare = search, locuri de munca = jobs.
Basically I want to make a small app that lets someone search for an existing job from the DB, in a specific county. (judet = county)
So how can I make pagination work? Right now when I change the page I get no results.

Related

User selected number of objects per page in Django

I made pagination for my site but I want to let the user choose how many records are displayed at one time e.g. 10, 15, 25. This is my views.py
def finished_ads_view(request):
queryset = Campaign.objects.filter(completion_percent=100)
try:
per_page = request.GET['dropdown']
except:
per_page = 1
page = request.GET.get('page', 1)
paginator = Paginator(queryset, per_page)
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
context = {
'posts': posts,
}
return render(request, 'finished_campaigns.html', context)
And this is part of my template:
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
{% if posts.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1" aria-label="Previous">
<span aria-hidden="true">«</span>
<span class="sr-only">begin</span>
</a>
</li>
{% endif %}
{% for n in posts.paginator.page_range %}
{% if posts.number == n %}
<li class="page-item active">
<span class="page-link">{{ n }}<span class="sr-only">(current)</span></span>
</li>
{% elif n > posts.number|add:'-3' and n < posts.number|add:'3' %}
<li class="page-item"><a class="page-link" href="?page={{ n }}">{{ n }}</a></li>
{% endif %}
{% endfor %}
{% if posts.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ posts.paginator.num_pages }}" aria-label="Next">
<span aria-hidden="true">»</span>
<span class="sr-only">end</span>
</a>
</li>
{% endif %}
</ul>
</nav>
<select name="dropdown">
<option value="1">1</option>
<option value="2">2</option>
<option value="15">15</option>
<option value="20">20</option>
</select>
<input type="submit" value="Submit"/>
</form>
The problem is that the dropdown value does not change and the number of records displayed at one time is still the same as the except: per_page value.
You should wrap your select and submit in a form so the value gets passed to the backend in query string.
<form method="get">
<input type="hidden" name="page" value="{{ page }}">
...
</form>
Also pagination parameter needs to be included so I added that. You need to add it to the context as well. Then when creating links for the pages with GET attribute don't forget to pass the dropdown as well.
To see the whole template can be better. I can only imagine:
<form>
<-- any staff here -->
<input type="hidden" name="page" value="{{ request.GET.page }}">
<-- any staff here -->
<select name="dropdown">
<option {% if request.GET.dropdown == "1" %}selected{% endif %}
value="1">1</option>
<option {% if request.GET.dropdown == "2" %}selected{% endif %}
value="2">2</option>
<option {% if request.GET.dropdown == "15" %}selected{% endif %} value="15">15</option>
<option {% if request.GET.dropdown == "20" %}selected{% endif %} value="20">20</option>
</select>
<-- any staff here -->
<input type="submit" />
<-- any staff here -->
</form>
Dont forget to add request in context, if you don't have request context processor.

Pagination in Django ListView when using get_context_data

I am currently facing this problem with Django ListView. Basically, I need to filter some questions per topic and I would like to paginate the results.
My code is working perfectly about the queryset part (the results are showed correctly) but I am facing a problem with pagination.
Let's say I have so far 8 items in my query, if I choose to paginate_by = 10, it shows me just one page. If, otherwise, I choose to paginate by, let's say, 3, it shows me 3 pages to choose in the template (which is correct) but it shows me ALL the results of the query in my page.
I post some code to be more clear
models.py:
class Tag(models.Model):
name = models.CharField(max_length=300, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def clean(self):
self.name = self.name.capitalize()
def __str__(self):
return self.name
class Question(models.Model):
post_owner = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=5000, default='')
body = tinymce_models.HTMLField()
tags = models.ManyToManyField(
Tag, related_name='tags')
viewers = models.ManyToManyField(
User, related_name='viewed_posts', blank=True)
views.py:
class TagQuestionsListView(ListView):
template_name = 'main/tag_questions.html'
paginate_by = 20
def get_queryset(self, **kwargs):
tag = Tag.objects.get(name=self.kwargs['name'])
questions = Question.objects.filter(tags=tag)
return questions
def get_contextdata(self, **kwargs):
context = super().get_context_data(**kwargs)
context['tag'] = Tag.objects.get(name=self.kwargs['name'])
context['questions'] = Question.objects.filter(
tags=context['tag'], is_deleted=False)
return context
template:
{% extends 'base.html' %}
{% load humanize %}
{% block title %}Domande su {{tag.name}}{% endblock title %}
{% block content %}
<style>
.text {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2; /* number of lines to show */
line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>
<div class="card">
<div class="mt-3">
<h3 class="ms-2" style="display: inline;">Ultime {{ questions.count }} Domande</h3>
{% if request.user.is_authenticated %}
Fai una domanda
{% else %}
Fai una domanda
{% endif %}
</div>
<h5 class="ms-2">{{ total_questions.count }} domande totali </h5>
<hr>
{% for question in questions %}
<div class="row">
<div class="col-2 ms-2">
<p>{{ question.count_all_the_votes }} Voti</p>
<p>{{ question.count_answers }} Risposte</p>
<p>{{ question.calculate_viewers }} Visualizzazioni</p>
</div>
<div class="col-9">
<h5>{{question.title}}</h5>
<div class="text">
{{ question.body|striptags }}
</div>
{% for tag in question.tags.all %}
<a class="btn btn-sm btn-outline-primary m-1" href="{% url 'main:tag_questions' name=tag.name %}">{{tag.name}}</a>
{% endfor %}
<div class="float-end">
<a style="display: inline;" href="">{{question.post_owner}}</a>
{% if question.is_edited == False %}
<span style="display:inline;">creata {{question.created_at | naturaltime}}</span>
{% else %}
<span style="display:inline;"> modificata {{question.edited_time | naturaltime}} da <a style="display: inline;" href="">{{question.edited_by.username}}</a></span>
{% endif %}
</div>
</div>
</div>
<hr>
{% endfor %}
</div>
<div class="row mt-3">
<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 'main:tag_questions' name=tag.name %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.previous_page_number }}">Precedente</a></li>
{% else %}
<li class="page-item disabled"><a class="page-link" href="#">Precedente</a></li>
{% endif %}
{% for i in paginator.page_range %}
<li class="page-item {% if page_obj.number == i%} active {% endif %} %} "><a class="page-link" href="?filter={{ filter }}&orderby={{ orderby }}&page={{ i }}">{{i}}</a></li>
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item"><a class="page-link" href="{% url 'main:tag_questions' name=tag.name %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.next_page_number }}">Prossima</a></li>
{% else %}
<li class="page-item disabled"><a class="page-link" href="#">Prossima</a></li>
{% endif %}
</ul>
</nav>
</div>
</div>
</div>
{% endblock content %}
With this I want my comment converter to answer.
You have to use page_obj instead questions in your template.
<--! ⬇️⬇️⬇️ -->
{% for question in page_obj %}
<div class="row">
<div class="col-2 ms-2">
<p>{{ question.count_all_the_votes }} Voti</p>
<p>{{ question.count_answers }} Risposte</p>
<p>{{ question.calculate_viewers }} Visualizzazioni</p>
</div>
<div class="col-9">
<h5>{{question.title}}</h5>
<div class="text">
{{ question.body|striptags }}
</div>
{% for tag in question.tags.all %}
<a class="btn btn-sm btn-outline-primary m-1" href="{% url 'main:tag_questions' name=tag.name %}">{{tag.name}}</a>
{% endfor %}
<div class="float-end">
<a style="display: inline;" href="">{{question.post_owner}}</a>
{% if question.is_edited == False %}
<span style="display:inline;">creata {{question.created_at | naturaltime}}</span>
{% else %}
<span style="display:inline;"> modificata {{question.edited_time | naturaltime}} da <a style="display: inline;" href="">{{question.edited_by.username}}</a></span>
{% endif %}
</div>
</div>
</div>
<hr>
{% endfor %}
So, if you define attribute paginate_by , than ListView(django docs) adds a paginator and page_obj to the context. To allow the users to navigate between pages, add links to the next and previous page, in your template.

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: Using a loop to output images and text from the db

I'm learning programming and following a tutorial using django 3, the same I'm using.
The text and images are not displaying on the frontend on one particular html file.
1.-In settings.py I have this:
MEDIA_ROOT= os.path.join(BASE_DIR,"media")
MEDIA_URL= "/media/"
2.-In models.py:
class Property(models.Model):
title = models.CharField(max_length=200)
main_photo = models.ImageField(upload_to='photos/%Y/%m/%d/')
3.-In admin.py:
from django.contrib import admin
from .models import Property
class PropertyAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'is_published')
list_display_links = ('id', 'title')
search_fields = ('title', 'town')
list_editable = ('is_published',)
list_per_page = 30
admin.site.register(Property, PropertyAdmin)
Then I migrated to the DB, I created a properties.html and the loop {{ property.main_photo.url }} or {{ property.title }} is working and getting images and texts on this properties file:
{% extends 'base.html' %}
{% load humanize %}
{% block content %}
<section id="showcase-inner" class="py-5 text-white">
<div class="container">
<div class="row text-center">
<div class="col-md-12">
<h1 class="display-4">Browse Our Properties</h1>
<p class="lead">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sunt, pariatur!</p>
</div>
</div>
</div>
</section>
<!-- Listings -->
<section id="listings" class="py-4">
<div class="container">
<div class="row">
{% if properties %}
{% for property in properties %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="card listing-preview">
<img class="card-img-top" src="{{ property.main_photo.url }}" alt="">
<div class="card-img-overlay">
<h2>
<span class="badge badge-secondary text-white">From {{ property.price_per_week | intcomma }}€ per week</span>
</h2>
</div>
<div class="card-body">
<div class="listing-heading text-center">
<h4 class="text-primary">{{ property.title }}</h4>
<p>
<i class="fas fa-map-marker text-secondary"></i> {{ property.town }}</p>
</div>
<hr>
<div class="row py-2 text-secondary">
<div class="col-6">
<i class="fas fa-check"></i> {{ property.swimming_pool }}</div>
<div class="col-6">
<i class="fas fa-wifi"></i> {{ property.free_wifi }}</div>
</div>
<div class="row py-2 text-secondary">
<div class="col-6">
<i class="fas fa-bed"></i> Bedrooms: {{ property.bedrooms }}</div>
<div class="col-6">
<i class="fas fa-bath"></i> Bathrooms: {{ property.bathrooms }}</div>
</div>
More Info
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="col-md-12">
<p>No Properties available</p>
</div>
{% endif %}
</div>
<div class="row">
<div class="col-md-12">
{% if properties.has_other_pages %}
<ul class="pagination">
{% if properties.has_previous %}
<li class="page-item">
<a href="?page={{properties.previous_page_number}}" class="page-link">«
</a>
</li>
{% else %}
<li class="page-item-disabled">
<a class="page-link">«</a>
</li>
{% endif %}
{% for i in properties.paginator.page_range %}
{% if properties.number == i %}
<li class="page-item active">
<a class="page-link">{{i}}</a>
</li>
{% else %}
<li class="page-item">
{{i}}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</div>
</div>
</div>
</section>
{% endblock %}
The next step is to create a property.html file and also use loop, but everything that uses the loop doble curly braces are not displaying:
{% extends 'base.html' %}
{% load humanize %}
{% block content %}
<section id="showcase-inner" class="py-5 text-white">
<div class="container">
<div class="row text-center">
<div class="col-md-12">
<h1 class="display-4">{{ property.title }}</h1>
<p class="lead">
<i class="fas fa-map-marker"></i> {{ property.town }}</p>
</div>
</div>
</div>
</section>
{% endblock %}
I checked multiple times and my code is exactly like on the tutorial but my frontend is not displaying.
Views.py:
from django.shortcuts import get_object_or_404, render
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from .models import Property
def index(request):
properties = Property.objects.get_queryset().order_by('id').filter(is_published=True)
paginator = Paginator(properties, 30)
page = request.GET.get('page')
paged_properties = paginator.get_page(page)
context = {
'properties': paged_properties
}
return render(request, 'properties/properties.html', context)
def property(request, property_id):
property = get_object_or_404(Property, pk=property_id)
context = {
'property': property
}
return render(request, 'properties/property.html')
def search(request):
return render(request, 'properties/search.html')
You are not passing the context to properties/property.html inside def property(..., ...)
Change:
return render(request, 'properties/property.html')
To:
return render(request, 'properties/property.html', context)

What's problem with this pagination code?

This code already have done the pagination ,but it false because per page it shows all items in the database ,and the same in other pages
This is the routing
#app.route('/shop/page/<int:page_num>')
def shop(page_num):
products=Product.query.filter
(Product.category.has(Product.category_id))
shopPage=Product.query.paginate
(page=page_num,per_page=5,error_out=True)
return render_template('shop.html',
shopPage=shopPage,products=products)
And this is the HTML code of pagination and the output products of database
{% block content %}
<div class="mb-5">
{% for product in products %}
<div class="col-4 mt-3 ">
<div class="card">
<div class="card-header">
<form method="POST" action="{{ url_for('shop') }}" >
</form>
</div>
<div class="card-body">
<h5 class="card-title">{{product.name }}</h5>
<p class="card-text">
<div>Category: {{ product.category.name }}</div>
<div>Price: {{ product.price }} $</div>
<div>Company: {{ product.company }}</div>
</p>
</div>
</div>
</div>
{% endfor %}
</div>
{% for page in shopPage.iter_pages(left_edge=2, right_edge=2, left_current=1, right_current=2) %}
{% if page %}
<nav >
<ul class="pagination ">
<li class="page-item ">
<a class="page-link" href="{{url_for('shop',page_num=page)}}" tabindex="-1">{{ page }}</a>
</li>
</ul>
</nav>
{% else %}
...
{% endif %}
{% endfor %}
{% endblock %}

Categories