Django's Generic ListView with django_filters and django_tables2

As an addendum to my last post, I needed to add additional features to the Customer List View. As I mentioned in my previous post on Django's Generic Class Based Views, I prefer to use class-based views (CBV's) in my projects whenever possible. This makes my application development fast, thorough and succinct. I can render a data table with pagination using only a few lines of code by inheriting from Django's generic base classes.

The other day though, I ran into a situation where I needed to provide a multi data-field filter in the Customer ListView for a CMS I'm working on developing. Django's generic CBV ListView does not provide a default method for receiving and processing a POST. We are going to need to override the default functionality. This is one of the things that make Django so extensible. I like that.

So, after a bit of reading.

The solution. Django Filter.

Django filters provides a simple way to filter a queryset based on parameters the user inputs. In my generic Customer ListView, I need to be able to search for customers by name, customer ID, email or telephone number. This is a pretty standard feature of any customer management system. Right?

First,

(.env)$ pip install django-filter

Next, django_tables2 contains a single class based view; SingleTableView. We'll use that to generate our table in our view.

I am going to separate my SingleTableView object from my views.py by using a utility file in which we will inherit the class as PagedFilteredTableView. The request object will be passed by keyword argument to the POST method of our Customer ListView's PagedFilteredTableView.as_view() function and return our filtered data as the view's context object.

filters.py
tables.py
utils.py
views.py
forms.py
urls.py

EDIT: I forgot to include the forms.py in the code example when I originally posted this article. Hope this helps clear up any confusion.

EDIT 2 (August 18th 2016): As requested, I have added the customers.html code to complete the example.

EDIT 3 (March 8th 2018): as requested, I have added a generic urls.py conf file to this post to help better complete the example.

customers.html
Result

PagedFilteredTableView

Wrapping Up

This solution works great.

My Customer ListView inherits from a subclass of Django Filters SingleTableView from utils.py. This allows me to setup a context object based on the filter passed in by the user's search form.

Next, since there is no default POST method for a Generic ListView, we have to override the ListView with a POST method that calls the PagedFilteredTableView.as_view() passing in the request object, which in our case is the GET parameters from the search form that is rendered in our template.

Craig Derington

Veteran full stack web dev focused on deploying high-performance, responsive, modern web applications using Python, NodeJS, Django, Flask, MongoDB and MySQL.

comments powered by Disqus