Django Filter, seacrh query and pagination - django

I have a problem using filters and pagination, I have tried so many examples I've seen here on stack overflow but nothing seems to be working. I am using CBV(ListView). The filter works but the pagination has an issue, when i click next or page 2 the filter breaks. I want the page to be paginated and show the remaining filtered items on the next page.
template.html
{% if is_paginated %}
{% if page_obj.has_previous %}
<a class="btn btn-info mb-4" href="?{% if object_list %}q={{ object_list }}&{% endif %}page={{ page_obj.previous_page_number }}">« Previous</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a class="btn btn-outline-info mb-4" href="?page={{ num }}">{{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a class="btn btn-info mb-4" href="?{% if object_list %}q={{ filter }}&{% endif %}page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="btn btn-info mb-4" href="?{% if object_list %}q={{ object_list }}&{% endif %}page={{ page_obj.next_page_number }}">Next</a>
<a class="btn btn-info mb-4" href="?{% if object_list %}q={{ object_list }}&{% endif %}page={{ page_obj.paginator.num_pages }}">Last «</a>
{% endif %}
{% endif %}
Then I used Django-filters but the filters breaks. How best will i achieve what i am looking for.
models.py
class Job(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
filters.py
class SearchFilter(django_filters.FilterSet):
title = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Job
fields = ('title',)
views.py
class SearchView(FilterView):
model = Job
template_name = 'search.html'
filterset_class = SearchFilter
ordering = ['-date']
paginate_by = 3
context_object_name = 'jobs'
strict = False
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filter'] = SearchFilter(self.request.GET, queryset=self.get_queryset())
return context

Add this in your get_context_data:
query = self.request.GET.copy()
if 'page' in query:
del query['page']
context['queries'] = query
and here is a complete listview pagination:
{% if is_paginated %}
{% if page_obj.has_previous %}
<li>
<i class="fa fa-angle-double-left"></i>
</li>
<li>
<i class="fa fa-angle-left"></i>
</li>
{% else %}
<li>
<i class="fa fa-angle-double-left"></i>
</li>
<li>
<i class="fa fa-angle-left"></i>
</li>
{% endif %}
{% for i in page_obj.paginator.page_range %}
{% if page_obj.number == i %}
<li>
{{ i }}
</li>
{% elif i > page_obj.number|add:'-4' and i < page_obj.number|add:'4' %}
<li>
{{ i }}
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li>
<i class="fa fa-angle-right"></i>
</li>
<li>
<i class="fa fa-angle-double-right"></i>
</li>
{% else %}
<li>
<i class="fa fa-angle-right"></i>
</li>
<li>
<i class="fa fa-angle-double-right"></i>
</li>
{% endif %}
{% endif %}

Related

Paginator won't paginate

I use Paginator for paginate my posts, i have no error, and i have the list of page in the bottom of the posts, but:
1.Post doesn't paginate correctly, i have set 5 i have more.
2. When i click on the 2 second page and 3 and etc, i have the same results of posts, i have no the next page with nexts posts.
This is my view code:
def post_all(request):
posts = Post.objects.filter().order_by('-published_date')
paginator = Paginator(posts, 5)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
categories = PostCategory.objects.all().annotate(posts_count=Count('post'))
return render(request, 'front/blog/post_all.html', {"posts":posts, "categories":categories,"page_obj":page_obj})
My template:
<!-- Pagination -->
<div class="pagination">
{% if page_obj.has_previous %}
<i class="fa fa-angle-left"></i>
{% endif %}
{{ page_obj.number }} de {{ page_obj.paginator.num_pages }}
{% if page_obj.has_next %}
<i class="fa fa-angle-right"></i>
{% endif %}
</div>
<!-- End Pagination -->
Thank u.
You could try using Class-based views.
Yours would be something like this :
views.py
from django.views.generic import (ListView)
class PostAllView(ListView):
model = Post
template_name = 'front/blog/post_all.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
ordering = ['-published_date']
paginate_by = 5
and a template.html that you can adapt to yours:
<h1>Total of posts : {{ page_obj.paginator.count }}</h1>
{% for post in posts %}
<article>
<p class="article-content">{{ post.content }}</p>
<!-- all the post related content you want to display here-->
</article>
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %}
<!-- you can adapt the class to your use-->
<a class="button" href="?page=1">First</a>
<a class="button" href="?page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a class="button-strong" href="?page={{ num }}">{{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a class="button" href="?page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="button" href="?page={{ page_obj.next_page_number }}">Next</a>
<a class="button" href="?page={{ page_obj.paginator.num_pages }}">Last</a>
{% endif %}
{% endif %}

How to add paginator and filter in your website?

I'm doing a project in which I need to display cars and the user is allowed to filter their queries based on price, make, model etc. Earlier today the filter was not working but the Paginator was, but now, the filter is working and the paginator is not. I've been stuck on this the whole day and I don't know what else to do.
This is my code:
views.py
def posts(request):
cars = Userpost.objects.all()
myFilter = UserpostFilter(request.GET, queryset=cars)
cars = myFilter.qs
p = Paginator(Userpost.objects.all(), 2)
page = request.GET.get('page')
cars_list = p.get_page(page)
nums = "a" * cars_list.paginator.num_pages
context = {'cars':cars, "myFilter":myFilter, 'cars_list':cars_list, "nums":nums}
return render(request, 'store/userposts.html', context)
userposts.html
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<div class = 'row'>
<div class = 'col'>
<div class = 'card card-body'>
<form method="get">
{{myFilter.form}}
<button class="btn btn-primary" type = "submit">Search</button>
</form>
</div>
</div>
</div>
<div class="row">
{% for car in cars %}
<div class="col-lg-4">
<img class="thumbnail" src="{{car.imageURL|default:'/images/transparentLogo.png'}}">
<div class="box-element product">
<h6><strong>{{car.Year}} {{car.Make}} {{car.Model}}</strong></h6>
<hr>
<a class="btn btn-outline-success" href="{% url 'post_detail' car.pk %}">View</a>
<h4 style="display: inline-block; float: right"><strong>${{car.Price|floatformat:2}}</strong></h4>
</div>
</div>
{% endfor %}
</div>
<nav aria-label="Page navigation"> <ul class="pagination">
{% if cars_list.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 cars_list.paginator.page_range %}
{% if cars_list.number == n %}
<li class="page-item active">
<span class="page-link">{{ n }}<span class="sr-only">(current)</span></span>
</li>
{% elif n > cars_list.number|add:'-3' and n < cars_list.number|add:'3' %}
<li class="page-item"><a class="page-link" href="?page={{ n }}">{{ n }}</a></li>
{% endif %}
{% endfor %}
{% if cars_list.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ cars_list.paginator.num_pages }}" aria-label="Next">
<span aria-hidden="true">»</span>
<span class="sr-only">end</span>
</a>
</li>
{% endif %} </ul> </nav>
<br/>
{% endblock content %}
filters.py
class UserpostFilter(django_filters.FilterSet):
start_date = DateFilter(field_name = "date_published", lookup_expr = 'gte')
end_date = DateFilter(field_name = "date_published", lookup_expr = 'lte')
min_price = django_filters.NumberFilter(field_name="Price", lookup_expr='gte')
max_price = django_filters.NumberFilter(field_name="Price", lookup_expr='lte')
class Meta:
model = Userpost
field = '__all__'
exclude = 'image', 'user', 'Price', 'Email', 'date_published'
I noticed that when i change the for loop on userposts.html to do "for car in cars_list", the pagination works but it breaks the filter, and using "for car in cars" makes the filter works but the pagination breaks.
I don't know what to do about it and I would really appreciate some help
try this
def posts(request):
cars = Userpost.objects.all()
myFilter = UserpostFilter(request.GET, queryset=cars)
if myFilter.qs:
cars = myFilter.qs
paginator = Paginator(cars, 2)
page = request.GET.get('page')
try:
cars = paginator.page(page)
except PageNotAnInteger:
cars = paginator.page(1)
except EmptyPage:
cars = paginator.page(paginator.num_pages)
context = {'cars_list':cars, "myFilter":myFilter}
return render(request, 'store/userposts.html', context)
template
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<div class = 'row'>
<div class = 'col'>
<div class = 'card card-body'>
<form method="get">
{{myFilter.form}}
<button class="btn btn-primary" type = "submit">Search</button>
</form>
</div>
</div>
</div>
<div class="row">
{% for car in cars_list %}
<div class="col-lg-4">
<img class="thumbnail" src="{{car.imageURL|default:'/images/transparentLogo.png'}}">
<div class="box-element product">
<h6><strong>{{car.Year}} {{car.Make}} {{car.Model}}</strong></h6>
<hr>
<a class="btn btn-outline-success" href="{% url 'post_detail' car.pk %}">View</a>
<h4 style="display: inline-block; float: right"><strong>${{car.Price|floatformat:2}}</strong></h4>
</div>
</div>
{% endfor %}
</div>
<nav aria-label="Page navigation"> <ul class="pagination">
{% if cars_list.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 cars_list.paginator.page_range %}
{% if cars_list.number == n %}
<li class="page-item active">
<span class="page-link">{{ n }}<span class="sr-only">(current)</span></span>
</li>
{% elif n > cars_list.number|add:'-3' and n < cars_list.number|add:'3' %}
<li class="page-item"><a class="page-link" href="?page={{ n }}">{{ n }}</a></li>
{% endif %}
{% endfor %}
{% if cars_list.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ cars_list.paginator.num_pages }}" aria-label="Next">
<span aria-hidden="true">»</span>
<span class="sr-only">end</span>
</a>
</li>
{% endif %} </ul> </nav>
<br/>
{% endblock content %}

Is there any way I can pass a filtered query set into Django's pagination?

view.py
def quiz(request):
question_topic = request.POST.getlist("topic_checkbox") # Retrieves list of topics selected by user
question_list = Quiz.objects.filter(Topic_name__in = question_topic) #filters out questions by topics
paginator = Paginator(question_list,1) # when i pass all the objects rather than the filtered query set it seems to work but when i paginate with the filtered queryset only the first page loads
page = request.GET.get('page')
try:
question_list = paginator.page(page)
except PageNotAnInteger:
question_list = paginator.page(1)
except EmptyPage:
question_list = paginator.page(paginator.num_pages)
return render(request,"Quiz/quiz_home.html",{"question_list":question_list})
quiz_home.html
{% block content %}
{% for q in question_list %} # loops through the filtered queryset
{% if question_list.has_next %}
<h3>Question {{q.id}}</h3>
<form method="POST" action="?page={{ question_list.next_page_number }}">{% csrf_token %}
# The form should enable me to gather the users input whilst simultaneoulsy going to the next question in the for loop. But when question sumbitted the next page is blank showing no contents
{% if q.picture %}
<img src="/media/{{q.picture}}"> <br>
{% endif %}
{{q.id}}.) </label><label id="question_text">{{q.question}}</label><br>
<input type="hidden" id= "q_id" name="q_id" value="{{q.id}}">
<input type="hidden" id= "topic" name="topic" value="{{q.topic}}">
<input type="radio" id="opt1" name="options" value="{{q.option1}}" required>{{ q.option1 }}<br>
<input type="radio" id="opt2" name="options" value="{{q.option2}}" required>{{ q.option2 }}<br>
<input type="radio" id="opt3" name="options" value="{{q.option3}}" required>{{ q.option3 }}<br>
<hr>
<input type="submit" id="mybtn" value="Submit"> #once clicked it should paginate to next page
</form>
{% else %}
<hr>
<form action="/home/">{% csrf_token %}
<input type="submit" name="End" value="End">
</form>
{% endif %}
{% endfor %}
{% endblock %}
Essentially im trying to filter out questions based on what topics the user has selected. This queryset of questions is then paginated so that each page shows one question.
I'll show you a pagination instance:
views.py
class CategoryDetail(ListView):
model = Task
template_name = 'category/category_detail.html'
context_object_name = 'task'
paginate_by = 5
def get_queryset(self):
self.category = get_object_or_404(Category,
pk=self.kwargs['pk'])
return Task.objects.filter(category=self.category).order_by('-id')
def get_context_data(self, *, object_list=None, **kwargs):
context = super(CategoryDetail, self).get_context_data(**kwargs)
self.category = get_object_or_404(Category, pk=self.kwargs['pk'])
# context['category'] = self.category
return context
category/category_detail.html
....
<div class="card-footer py-4">
{% if is_paginated %}
<nav aria-label="...">
<ul class="pagination justify-content-end mb-0">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" tabindex="-1">
<i class="fas fa-angle-left"></i>
<span class="sr-only">Previous</span>
</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1">
<i class="fas fa-angle-left"></i>
<span class="sr-only">Previous</span>
</a>
</li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="page-item active">
<a class="page-link" href="#"> {{ i }} </a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ i }}">{{ i }}<span class="sr-only">(current)</span></a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}">
<i class="fas fa-angle-right"></i>
<span class="sr-only">Next</span>
</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#">
<i class="fas fa-angle-right"></i>
<span class="sr-only">Next</span>
</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
Django already has a ready-made paging structure. You can use it in your Html file you want to use.

Django Pagination - Object list not looping in template

I'm attempting to use pagination on my notifications page for a user (list of all notifications). When I add the code for pagination:
def notificationList(request, pk):
notifications = Notification.objects.all()
paginator = Paginator(notifications, 5)
page = request.GET.get('page')
try:
notifications = paginator.page(page)
except PageNotAnInteger:
notifications = paginator.page(1)
except EmptyPage:
notifications = paginator.page(paginator.num_pages)
context = {'notifications': notifications }
return render(request, 'user/notifications.html', context)
The result is this:
However, when I comment out all pagination related code in views.py, all the notifications appear on the page (pagination appears). So I know it's not that I'm not accessing my notification object list incorrectly/returning an empty queryset. Here is the notifications.html pagination code:
{% if notifications.has_other_pages %}
<ul class="pagination justify-content-center mb-4">
{% if notifications.has_previous %}
<li class="page-item"><a class="page-link" href="?page={{ notifications.previous_page_number }}">«</a></li>
{% else %}
<li class="disabled page-item"><span class="page-link">«</span></li>
{% endif %}
{% for i in notifications.paginator.page_range %}
{% if notifications.number == i %}
<li class="active page-item"><span class="page-link">{{ i }} <span class="sr-only page-item">(current)</span></span></li>
{% else %}
<li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if notifications.has_next %}
<li class="page-item"><a class="page-link" href="?page={{ notifications.next_page_number }}">»</a></li>
{% else %}
<li class="disabled page-item"><span class="page-link">»</span></li>
{% endif %}
</ul>
{% endif %}
Here is where I render the notifications in the template:
{% for notification in notifications %}
<div class="row">
<div class="col">
{% if notification.read == False %}
<span class="badge badge-primary">New</span>
{% elif notification.read == True %}
<span class="badge badge-success">Read</span>
{% endif %}
</div>
<div class="col">
<a class="btn btn-sm btn-info" href="{% url 'offer-details' notification.offer_id %}">View</a>
</div>
<div class="col">
{% if notification.type_of_notification == "O" %}
<p>An offer has been made for one of your repairs!</p>
{% elif notification.type_of_notification == "P" %}
<p>A payment has been made on a repair!</p>
{% elif notification.type_of_notification == "OR" %}
<p>Sorry, your offer for a repair has been rejected.</p>
{% elif notification.type_of_notification == "OC" %}
<p>An offer for your repair has been canceled!</p>
{% endif %}
</div>
<div class="col">
{{notification.created_at}}
</div>
</div>
<hr>
{% endfor %}

That page contains no results Django ListView

I have the problem in Django 1.9
I have this problem when I go to the last result pagination
views.py
class UserList(ListView):
model = User
template_name = 'account/users.html'
paginate_by = 1
users.html
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
I've encountered this as well and the problem is that Paginator.page_range is 1-based.
https://docs.djangoproject.com/en/1.9/topics/pagination/#django.core.paginator.Paginator.page_range
I've used the following solution: (I'm using Foundation 6)
{% if is_paginated %}
<ul class="pagination text-center" role="navigation" aria-label="Pagination">
{% if page_obj.has_previous %}
<li class="pagination-previous">
<a href="?page={{ page_obj.previous_page_number }}">
<span>Previous</span>
</a>
</li>
{% else %}
<li class="pagination-previous disabled">
<span>Previous</span>
</li>
{% endif %}
{% for page in paginator.page_range %}
{% if paginator.num_pages != page %}
<li class="{% if page == page_obj.number %}active{% endif %}">
{{ page }}
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next and paginator.num_pages != page_obj.next_page_number %}
<li class="pagination-next">
<a href="?page={{ page_obj.next_page_number }}">
<span>Next</span>
</a>
</li>
{% else %}
<li class="pagination-next disabled">
<span>Next</span>
</li>
{% endif %}
</ul>
{% endif %}
Hope this helps! I initially based my code from https://ana-balica.github.io/2015/01/29/pagination-in-django/