Reputation: 2392
I am very new at this technology and I want to paginate a table containing results using django_filter (In my case I want to filter results from Book Model which are displayed in a HTML Table).
I tried every documentation and forum post but don't know what I am doing wrong or if I am doing something correctly.
Here is my code:
models
class Book(models.Model):
name = models.CharField(max_length=350)
author = models.CharField(max_length=350)
category = models.CharField(max_length=200)
def __str__(self):
return self.name
filters
class BookFilter(django_filters.FilterSet):
name = django_filters.CharFilter(lookup_expr='icontains')
author = django_filters.CharFilter(lookup_expr='icontains')
category = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Book
ields = ['name', 'author', 'category',]
views
class SearchBooksView(ListView):
template_name = "booksearch.html"
book_list = Book.objects.all()
context_object_name = 'book_list'
paginate_by = 3
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
book_filter = BookFilter(self.request.GET)
paginator = Paginator(book_filter, self.paginate_by)
page = self.request.GET.get('page')
try:
book_list = paginator.page(page)
except PageNotAnInteger:
book_list = paginator.page(1)
except EmptyPage:
book_list = paginator.page(paginator.num_pages)
context['book_list'] = book_list
return context
** html **
<h1 class="h1"> Search Books </h1>
<form method="get">
{{ book_filter.form.as_p }}
<button type="submit">Search</button>
</form>
<div class="container">
<table>
<thead>
<tr>
<th>Name</th>
<th>Author</th>
<th>Category</th>
</tr>
</thead>
<tbody>
{% for book in book_list %}
<tr>
<td>{{ book.name }}</td>
<td>{{ book.author }}</td>
<td>{{ book.category }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if is_paginated %}
<ul class="pagination">
{% if page_obj.has_previous %}
<li>
<span><a href="?page={{ page_obj.previous_page_number }}">Previous</a></span>
</li>
{% endif %}
<li class="">
<span>Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.</span>
</li>
{% if page_obj.has_next %}
<li>
<span><a href="?page={{ page_obj.next_page_number }}">Next</a></span>
</li>
{% endif %}
</ul>
{% else %}
<p>No books available</p>
{% endif %}
</div>
with this code I am getting :
paginator.py, line 84, in count return len(self.object_list)
'BookFilter' has no len()
Can you please help me? Thanks!
Upvotes: 0
Views: 275
Reputation: 3805
You are using generic ListView from django right? That view already take care of pagination for you, you should refactor the code:
class SearchBooksView(ListView):
model = Book
template_name = "booksearch.html"
context_object_name = 'book_list'
paginate_by = 3
def get_queryset(self):
return BookFilter(self.request.GET, queryset=Book.objects.all()).qs
Upvotes: 0
Reputation: 1461
You need to pass the filtered queryset to the Paginator which can be accessed as filterObj.qs
.
From the django_filter docs:
If you want to access the filtered objects in your views, for example if you want to paginate them, you can do that. They are in f.qs
So create a paginated response like this:
book_filter = BookFilter(self.request.GET)
paginator = Paginator(book_filter.qs, self.paginate_by)
Upvotes: 2