Reputation: 1264
I'm trying to do a ListView from a Class Based View that has filtering, and pagination
I was able to get the table showing and the pagination working as I want, this gives me a basic list of all invoices that I need to show:
but I'm not able to make the filtering work, for what I understand I need to override the "get_queryset" method and this would return a queryset, (in this cased called "invoices_filtered_list") however I don't know how should I render this in the .html page so it will have the textbox in which I should type.
These are my files:
views.py
from django.views.generic import (TemplateView, ListView)
from .models import WoodhistAzolveInvoices
from .filters import WoodhistAzolveInvoicesFilter
class InvoicesListView(ListView):
model = WoodhistAzolveInvoices
template_name = 'home.html'
context_object_name = 'invoices'
ordering = ['suppliername', 'invoicenumber']
paginate_by = 50
def get_queryset(self):
qs = self.model.objects.all()
invoices_filtered_list = WoodhistAzolveInvoicesFilter(self.request.GET, queryset=qs)
return invoices_filtered_list.qs
urls.py
from django.urls import path
from .views import InvoicesListView
app_name = 'web'
urlpatterns = [
path('', InvoicesListView.as_view(), name='home'),
]
filters.py
import django_filters
from .models import *
class WoodhistAzolveInvoicesFilter(django_filters.FilterSet):
class Meta:
model = WoodhistAzolveInvoices
fields = ['suppliername']
models.py
from django.db import models
class WoodhistAzolveInvoices(models.Model):
docid = models.CharField(db_column='DocId', primary_key=True, max_length=50) # Field name made lowercase.
supplierreference = models.CharField(db_column='SupplierReference', max_length=50, blank=True, null=True) # Field name made lowercase.
suppliername = models.CharField(db_column='SupplierName', max_length=100, blank=True, null=True) # Field name made lowercase.
invoicenumber = models.CharField(db_column='InvoiceNumber', max_length=50, blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'WoodHist_Azolve_Invoices'
home.html
{% extends "base.html" %}
{% block title %} base title {% endblock title %}
{% block content %}
<h1> azolve home </h1>
<div class="row">
<div class="col">
<div class="card card-body">
<form method="get">
{{ invoices_filtered_list.form }}
<button class="btn btn-primary" type="submit">Search</button>
</form>
</div>
</div>
</div>
<table id="myTable1" class="table table-striped table-bordered" style="width:100%">
<thead>
<tr>
<th scope="col">Supplier Name</th>
<th scope="col">Invoice Number</th>
<th scope="col">Reference</th>
</tr>
</thead>
<tbody>
{% for datarow in invoices %}
<tr>
<td>{{datarow.suppliername}}</td>
<td>{{datarow.invoicenumber}}</td>
<td>{{datarow.supplierreference}}</td>
</tr>
{% endfor %}
{% if is_paginated %}
{% if page_obj.has_previous %}
<a class="btn btn-outline-info" href="?page=1">First</a>
<a class="btn btn-outline-info" 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="btn btn-info" href="?page={{ num }}"> {{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a class="btn btn-outline-info" href="?page={{ num }}"> {{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="btn btn-outline-info" href="?page={{ page_obj.next_page_number }}">Next</a>
<a class="btn btn-outline-info" href="?page={{ page_obj.paginator.num_pages }}">Last</a>
{% endif %}
{% endif %}
</tbody>
</table>
{% endblock content %}
If it worth noting, I'm using the package "django_filters" and Django 3.2.4
Upvotes: 1
Views: 1029
Reputation: 2380
You want filtering and pagination at the same time.
you need to make your pagination to keep your querystrings
then you can have them at the same time. Because when you click on next page your querystring will be like this .../?page=page_number
so your filtering will be gone.
you can do this:
Inside your app directory create a folder called templatetags
.
Inside the templatetags folder create a file called pagination_tags.py
(name is up to you).
# Your template tag in app_name/templatetags/pagination_tags.py
from django import template
from urllib.parse import urlencode
register = template.Library()
@register.simple_tag
def url_replace (request, field, value):
dict_ = request.GET.copy()
dict_[field] = value
return dict_.urlencode()
After creating your template tag load it in your html page and use it.
{% load pagination_tags %}
{% if is_paginated %}
<nav aria-label="Page navigation example" class="d-flex justify-content-center pt-3">
<ul class="pagination">
{% if page_obj.has_previous and page_obj.number != 2 %}
<li class="page-item"><a class="page-link text-dark" href="?{% url_replace request 'page' 1 %}" tabindex="-1" aria-disabled="true">First Page</a></li>
{% endif %}
{% if page_obj.has_previous %}
<li class="page-item"><a class="page-link text-dark" href="?{% url_replace request 'page' page_obj.previous_page_number %}">{{ page_obj.previous_page_number }}</a></li>
{% endif %}
<li class="page-item disabled"><a class="page-link" href="#">{{ page_obj.number }}</a></li>
{% if page_obj.has_next %}
<li class="page-item"><a class="page-link text-dark" href="?{% url_replace request 'page' page_obj.next_page_number %}">{{ page_obj.next_page_number }}</a></li>
{% endif %}
{% if page_obj.paginator.num_pages != page_obj.number and page_obj.paginator.num_pages != page_obj.next_page_number %}
<li class="page-item"><a class="page-link text-dark" href="?{% url_replace request 'page' page_obj.paginator.num_pages %}">Last Page</a></li>
{% endif %}
</ul>
</nav>
{% endif %}
And your ListView
should be replaced by FilterView
from django_filters.views import FilterView
from .models import WoodhistAzolveInvoices
from .filters import WoodhistAzolveInvoicesFilter
class InvoicesListView(FilterView):
model = WoodhistAzolveInvoices
template_name = "home.html"
filterset_class = WoodhistAzolveInvoicesFilter
context_object_name = 'invoices'
ordering = ['suppliername', 'invoicenumber']
paginate_by = 50
Upvotes: 1