In Django REST Framework (DRF), APIView does not support Django Filter Backend directly. Typically, Django Filter Backend works with GenericAPIView
and above, but when using APIView, filtering must be implemented manually.
Especially when retrieving chart data or handling custom processing in an API, APIView is often preferred due to its flexibility in data processing and transformation. This article explains how to implement AND / OR filtering within APIView.
Additionally, when working with chart data or similar use cases, defining the same filtering logic in multiple views can be inefficient. To address this, we will introduce a shared filter class that can be inherited and reused across different views.
After learning this, you will be able to:
- Apply AND conditions to specific parameters while applying OR conditions to others.
- Use
|
to specify multiple OR values dynamically. - Modularize filter processing by creating a reusable filter class for multiple views.
By following this approach, you can ensure API flexibility, reduce code redundancy, and maintain a clean and scalable architecture.
Database Model (models.py)
Before diving into the implementation, let’s check the structure of the data we will use. Understanding what kind of data will be filtered makes the implementation more intuitive.
Below is an example of the database model used in this article:
from django.db import models
class testData(models.Model):
type = models.CharField(max_length=255, blank=True, null=True)
ItemName = models.CharField(max_length=255, blank=True, null=True)
category = models.CharField(max_length=255, blank=True, null=True)
ItemNum = models.IntegerField(blank=True, null=True)
ItemColor = models.CharField(max_length=255, blank=True, null=True)
baseDate = models.DateField(blank=True, null=True)
class Meta:
managed = False
db_table = 'testData'
objects = models.Manager()
Sample Data
id | type | ItemName | category | ItemNum | ItemColor | baseDate |
---|---|---|---|---|---|---|
1 | α | A1 | 1 | 1 | #13bda2 | 2025-01-01 |
2 | α | B1 | 1 | 1 | #0c8c88 | 2025-01-01 |
3 | β | B1 | 1 | 1 | #0c8c88 | 2025-01-01 |
4 | α | C1 | 1 | 1 | #016370 | 2025-01-01 |
5 | β | C1 | 2 | 1 | #016370 | 2025-01-01 |
6 | α | D1 | 4 | 1 | #173037 | 2025-01-01 |
Implementing AND / OR Filtering in APIView
Overview of AND / OR Conditions
When filtering data, the following conditions are applied:
type
andcategory
follow OR conditions (any matching value is valid)ItemNum
andItemColor
follow AND conditions (all specified conditions must match)category
can specify multiple values separated by|
to apply an OR condition
Creating a Reusable Filter Class
from django.db.models import Q
class BaseFilter:
OR_PARAMS = ['type', 'category'] # Parameters that follow OR conditions
AND_PARAMS = ['ItemNum', 'ItemColor'] # Parameters that follow AND conditions
def apply_filters(self, queryset, filters):
query = Q()
for param, value in filters.items():
values = value.split('|') # Split multiple values by '|'
tmp_query = Q()
for v in values:
tmp_query |= Q(**{param: v}) # Create an OR condition for multiple values
if param in self.AND_PARAMS:
query &= tmp_query # Apply AND condition for specified parameters
else:
query |= tmp_query # Apply OR condition for other parameters
return queryset.filter(query)
Implementing APIView
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import testData
from .filters import BaseFilter
class FilterAPIView(APIView, BaseFilter):
def get(self, request):
queryset = testData.objects.all() # Retrieve all records from the database
filtered_queryset = self.apply_filters(queryset, request.GET) # Apply filters to the queryset
return Response(filtered_queryset.values()) # Return the filtered data as a response
Example Request
GET /api/filter/?type=α&category=1|2&ItemNum=1&ItemColor=#0c8c88
Applied Filtering Conditions:
type
is ‘α’ ORcategory
is ‘1’ OR ‘2’- AND
ItemNum
is ‘1’ ANDItemColor
is ‘#0c8c88’
SQL Representation:
SELECT * FROM testData
WHERE (ItemNum = 1 AND ItemColor = '#0c8c88')
AND (type = 'α' OR category = '1' OR category = '2');
This article introduced how to dynamically apply AND / OR conditions when using APIView. By utilizing the Q
object and allowing multiple OR conditions with |
, we achieved flexible filtering.
Additionally, we implemented a reusable common filter through class inheritance, allowing us to standardize the filter logic. This approach makes it easy to apply filtering to different APIs while improving maintainability.
By leveraging this method, you can build more flexible and extensible APIs! 🚀