Prerequisite: Adding Filtering in APIs – Django REST Framework [link needed article on published yet]
Django filters facilitate filtering the queryset to retrieve the relevant results based on the values assigned to the filter fields. But, what if the user wants to retrieve details within a given range. Say, for example, the user needs to fetch detail of robots based on price range. Here comes the necessity of customizing the filters. Let’s create and apply a customized filter to the Robot model so that the user can retrieve robot details by providing robot category name, manufacturer name, currency, manufacturing date range, and/or price range.
We will create a new class named RobotFilter class, which is a subclass of django_filters.FilterSet class. Let’s declare the imports
Python3
from django_filters import FilterSet, AllValuesFilter from django_filters import DateTimeFilter, NumberFilter |
Now, you can add the below code before the RobotList class.
Python3
class RobotFilter(FilterSet): from_manufacturing_date = DateTimeFilter(field_name = 'manufacturing_date' , lookup_expr = 'gte' ) to_manufacturing_date = DateTimeFilter(field_name = 'manufacturing_date' , lookup_expr = 'lte' ) min_price = NumberFilter(field_name = 'price' , lookup_expr = 'gte' ) max_price = NumberFilter(field_name = 'price' , lookup_expr = 'lte' ) robotcategory_name = AllValuesFilter(field_name = 'robot_category__name' ) manufacturer_name = AllValuesFilter(field_name = 'manufacturer__name' ) class Meta: model = Robot fields = ( 'name' , 'currency' , 'from_manufacturing_date' , 'to_manufacturing_date' , 'min_price' , 'max_price' , 'robotcategory_name' , 'manufacturer_name' , ) |
Let’s look at the attributes declared in the RobotFilter class.
- from_manufacturing_date
- to_manufacturing_date
- min_price
- max_price
- robotcategory_name
- manufacturer_name
from_manufacturing_date: It is a django_filters.DateTimeFilter instance attribute that filters the robots whose manufacturing_date value is greater than or equal to the specified DateTime value. Here in the DateTimeFilter, there are two parameters named field_name and lookup_expr. The field_name has the manufacturing_date (for filtering), and ‘gte’ (greater than or equal to) is applied to the lookup_expr.
to_manufacturing_date: It is a django_filters.DateTimeFilter instance attribute that filters the robots whose manufacturing_date value is less than or equal to the specified DateTime value. Here in the DateTimeFilter, there are two parameters named field_name and lookup_expr. In the field_name, we mentioned the manufacturing_date, and ‘lte’ (less than or equal to) is applied to the lookup_expr.
min_price: It is a django_filters.NumberFilter instance attribute that filters the robots whose price value is greater than or equal to the specified price value.
max_price: It is a django_filters.NumberFilter instance attribute that filters the robots whose price value is less than or equal to the specified price value.
robotcategory_name: It is a django_filters.AllValuesFilter instance attribute that filters the robots whose robot category name matches with the specified string value. You can notice that there is a double underscore (__) in the value provided to the field_name, between robot_category and name. The field_name uses the Django double underscore to read it as the name field for the RobotCategory model. This helps to retrieve the robot’s detail based on the robot category name rather than its pk id.
manufacturer_name: It is a django_filters.AllValuesFilter instance attribute that filters the robots whose manufacturer name matches with the specified string value. The field_name uses the Django double underscore to read the value ‘manufacturer__name’ as the name field for the Manufacturer model. This helps to retrieve the robot’s detail based on the manufacturer name rather than its pk id.
The RobotFilter class also defines a Meta inner class. This class has two attributes model and fields. The model attribute specifies the model (Robot) to filter. And, the fields attribute holds field names and filter names (as a tuple of strings) to include in the filters for the mentioned model (Robot).
Let’s use the RobotFilter class in our RobotList class. The code as follows
Python3
class RobotList(generics.ListCreateAPIView): queryset = Robot.objects. all () serializer_class = RobotSerializer name = 'robot-list' # customized filter class filter_class = RobotFilter search_fields = ( '^name' , ) ordering_fields = ( 'price' , ) |
Let’s filter the robots within a manufacturing date. The HTTPie command is
http “:8000/robot/?from_manufacturing_date=2019-10-01&to_manufacturing_date=2020-03-01”
Output:
Let’s filter the robots based on the robot category name and manufacturer name. The HTTPie command as follows
http “:8000/robot/?robotcategory_name=Articulated Robots&manufacturer_name=Fanuc”
Output:
Let’s filter the robots based on price range. The HTTPie command is
http “:8000/robot/?min_price=10000&max_price=20000¤cy=USD”
Output:
Let’s filter the robots using the browsable API feature. You can browse the below URL and click the filter button.
http://127.0.0.1:8000/robot/
You can populate the values to filter against robots. Sharing the screenshot below
On clicking the submit button, you will get filtered results. Sharing the screenshot below