When you have multiple entries in your table, sometimes it becomes difficult to find the specific information that you need. To solve that problem with ease Django has a package called django-filters. In this blog, we will show you how you can implement a search filter step by step.
Objective: To be able to filter the entries in your table based upon its table field values.
Prerequisite: A Django Web-app which displays data in your template rendering the items from any database you have chosen.
If you haven’t developed your web-app yet than do follow our Django Tutorial series and build one now.
While we will be including different codes below, it is important for you to understand the flow of this executing. This is how we are going to procees:
- Install package django-filters
- Register the package in settings.py
- Create a model named Order
- Create a View customer
- Create a Filter using django_filters
- Include the filter in customer
- Reflect the filter form in Template
- Exclude fields from the Django Filter Form
- Filter Dates and Characters using DateFilter and CharFilter
If you have your web app ready and also have a template that renders data from a table you might wanna skip steps 3 and 4.
Install package django-filters
From your terminal install django filters by typing the following command:
pip install django-filters
Register the Package in settings.py
Like django-admin, authentication, session, messages and emails, django-filter is also another package provided by django. Therefore it is necessary to let your web-applicaiton know that it is working with some new packages. So add django_filters in our settings.py, installed applications sections like this:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'account', 'django_filters', ]
Above, account is the web app I am developing and below that I registered django_filters.
Remember we installed dajgo-filters package but have registered django_filters in INSTALLED_APPS. This is how it is.
Create Model Order
In this section we will not display all the CRUD operation to fetch and update the items from a table. However we require a model to understand what data we are going to filter from the table. Therefore in your mdoels.py file create a model named Order like shown below:
class Order(models.Model):
STATUS=(
('Pending', 'Pending'),
('Out for delivery', 'Out for delivery'),
('Delivered', 'Delivered')
)
customer = models.ForeignKey(Customer, null=True, on_delete=models.SET_NULL)
product = models.ForeignKey(Products, null=True, on_delete=models.SET_NULL)
date_created = models.DateTimeField(auto_now_add=True, null=True)
status = models.CharField(max_length=200, null=True, choices=STATUS)
note = models.CharField(max_length=1000, null=True)
In our case the product details are referenced by Foreign Key to the table Products. So all information in product is retrieved from there only. But you can make it another CharField like that of the note.
Create a View customer
Initially let’s create a view customer that renders all contents from the order table. These orders are the orders made by particular customer:
def customer(request, pk):
customer = Customer.objects.get(id=pk)
orders = customer.order_set.all()
context = {'orders': orders}
return render(request, 'account/customer.html', context)
This fetches all the orders from a customer.
Note: We will not cover the specific order according to the customer id. This needs to cover additional work at routing. For that extra information visit our Django Tutorial Series
Create a Filter using django_filters
In a new file (filters.py), we will implement Django filters for your table and implement it on our views. First import django_filters and all models.
import django_filters
from .models import *
class OrderFilter(django_filters.FilterSet):
class Meta:
model = Order
fields = '__all__'
With this code, you can apply the filter to all the orders. Now we have to add this logic to the customer view and also reflect the change in the template.
Include the filter in customer
Now, we need to include the OrderFilter in customer view. To do so include OrderFilter like shown below:
from .filters import OrderFilter
def customer(request, pk):
customer = Customer.objects.get(id=pk)
orders = customer.order_set.all()
tableFilter = OrderFilter(request.GET, queryset=orders)
orders = myFilter.qs
context = {‘orders’: orders, ‘tableFilter’: tableFilter}
return render(request, ‘account/customer.html’, context)
tableFilter does the work of applying filter to all fields of Orders for a customers. Next is the last job to reflect the table filter in our template.
Reflect the filter form in Template
In this example we are displaying the orders made by a customer. So we are going to create the customer.html and make some modification to reflect the table filter for all the orders.
<div class="row">
<div class="col-md">
<div class="card card-body">
<table class="table table-sm">
<tr>
<th>Product</th>
<th>Category</th>
<th>Date Orderd</th>
<th>Note</th>
<th>Status</th>
</tr>
{% for order in orders %}
<tr>
<td>{{order.product}}</td>
<td>{{order.product.category}}</td>
<td>{{order.date_created}}</td>
<td>{{order.note}}</td>
<td>{{order.status}}</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
Code above only displays the order details of a customer. Next, we will add another division where we will add the table filter. We can render the table filter just like a form. So code below adds a table form filter made with Django:
<div class="row">
<div class="col">
<div class="card card-body">
<form method="get">
{{tableFilter.form}}
<button class="btn btn-primary" type="submit">Search</button>
</form>
</div>
</div>
</div>
Exclude fields from the Django Filter Form
Now with this, we can filter the contents from the orders for a customer. But we might wanna do some more things. You might want to discard certain entries in the filter form. In order to discard, say, the name of customers or the long timestamp you need to do the following in your filters.py:
import django_filters
from .models import *
class OrderFilter(django_filters.FilterSet):
class Meta:
model = Order
fields = '__all__'
exclude = ['customer', 'date_created']
Filter Dates and Characters using DateFilter and CharFilter
Finally, if we have to apply some other filters such as filtering a date or ignoring the case sensitivity in your search area. You can apply those filters as well from django_filters.
- Say you want to find the items which have the word Hello in your note section. The word hello can either be upper case or lower case.
- Also, you might want to search the items ordered after or before a certain date.
Than we can do so using DateFilter and CharFilter like shown below:
import django_filters
from django_filters import DateFilter, CharFilter
from .models import *
class OrderFilter(django_filters.FilterSet):
start_date = DateFilter(field_name="date_created", lookup_expr='gte')
end_date = DateFilter(field_name="date_created", lookup_expr='lte')
note = CharFilter(field_name='note', lookup_expr='icontains')
class Meta:
model = Order
fields = '__all__'
exclude = ['customer', 'date_created']
In start date and end date, the terms gte and lte are “greater than or equal to” and “less than or equal to” respectively. Also with the lookup expression icontains it ignores the case sensitivity.