在 Django REST Framework (DRF) 中,结合 django-filter 可以实现强大的过滤功能,而自定义过滤类能满足更复杂的业务需求。以下是具体的使用方法:
一、准备工作
-
安装依赖首先安装
django-filter:pip install django-filter -
注册应用在
settings.py中注册django_filters:INSTALLED_APPS = [ # ... 'django_filters', ]
二、基础使用:快速启用过滤
在 DRF 视图中直接使用 django-filter 提供的 DjangoFilterBackend,可快速实现基于模型字段的过滤。
示例模型
假设存在一个 Book 模型:
# models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
price = models.DecimalField(max_digits=5, decimal_places=2)
publication_date = models.DateField()
视图中启用过滤
# views.py
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from .models import Book
from .serializers import BookSerializer
class BookViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 启用 django-filter 后端
filter_backends = [DjangoFilterBackend]
# 指定允许过滤的字段(精确匹配)
filterset_fields = ['author', 'price'] # 支持 ?author=鲁迅&price=39.99
三、自定义过滤类:实现复杂过滤逻辑
当基础过滤无法满足需求(如范围查询、模糊匹配、跨字段关联等),可通过自定义过滤类实现。
步骤 1:定义自定义过滤类
继承 django_filters.FilterSet,并通过 Meta 类关联模型,同时定义自定义过滤字段。
# filters.py
import django_filters
from .models import Book
class BookFilter(django_filters.FilterSet):
# 1. 模糊匹配(标题包含某个关键词)
title_contains = django_filters.CharFilter(field_name='title', lookup_expr='icontains')
# 2. 价格范围过滤(大于等于min_price,小于等于max_price)
min_price = django_filters.NumberFilter(field_name='price', lookup_expr='gte')
max_price = django_filters.NumberFilter(field_name='price', lookup_expr='lte')
# 3. 日期范围(出版日期在某个区间)
pub_date_after = django_filters.DateFilter(field_name='publication_date', lookup_expr='gte')
# 4. 自定义方法过滤(例如:价格是否低于平均值)
price_below_average = django_filters.BooleanFilter(method='filter_price_below_average')
class Meta:
model = Book
# 额外支持的基础过滤字段(精确匹配)
fields = ['author'] # 结合自定义字段,总过滤参数包括 author、title_contains 等
# 实现自定义方法过滤
def filter_price_below_average(self, queryset, name, value):
if value: # 当参数为 True 时生效
avg_price = queryset.aggregate(avg=models.Avg('price'))['avg'] or 0
return queryset.filter(price__lt=avg_price)
return queryset
- 核心参数说明
field_name:指定关联的模型字段。lookup_expr:指定查询表达式(如icontains模糊匹配、gte大于等于等,支持 Django ORM 所有查询表达式)。method:自定义过滤方法(接收queryset、name、value三个参数,返回处理后的查询集)。
步骤 2:在视图中应用自定义过滤类
在视图中通过 filterset_class 指定自定义过滤类,替代基础的 filterset_fields。
# views.py
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend
from .models import Book
from .serializers import BookSerializer
from .filters import BookFilter # 导入自定义过滤类
class BookViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [DjangoFilterBackend]
# 应用自定义过滤类
filterset_class = BookFilter
步骤 3:使用过滤参数
启动服务后,可通过 URL 参数调用过滤功能,例如:
- 模糊查询标题包含 “Python” 的书籍:
?title_contains=Python - 查询价格在 20 到 50 之间的书籍:
?min_price=20&max_price=50 - 查询 2023 年 1 月 1 日后出版的书籍:
?pub_date_after=2023-01-01 - 查询价格低于平均值的书籍:
?price_below_average=true
四、高级技巧
-
结合搜索和排序可同时启用 DRF 的
SearchFilter和OrderingFilter,与DjangoFilterBackend配合使用:from rest_framework.filters import SearchFilter, OrderingFilter class BookViewSet(viewsets.ReadOnlyModelViewSet): # ... filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter] search_fields = ['title', 'author'] # 支持全文搜索 ordering_fields = ['price', 'publication_date'] # 支持排序 ordering = ['-publication_date'] # 默认排序 -
动态过滤逻辑在自定义过滤类的
__init__方法中,可根据请求参数动态调整过滤规则(例如基于用户权限过滤)。 -
关联模型过滤支持通过双下划线
__关联外键字段,例如过滤某出版社的书籍:class BookFilter(django_filters.FilterSet): publisher_name = django_filters.CharFilter(field_name='publisher__name', lookup_expr='icontains')
通过自定义过滤类,django-filter 可以灵活满足各种复杂的过滤需求,结合 DRF 的视图集和序列化器,能快速构建强大的 API 过滤功能。
评论区 0