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?
(.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.
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.
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.