SearchFilter 详解
SearchFilter
是 Django REST Framework(DRF)提供的一个过滤器 ,用于在 ModelViewSet
视图集中支持搜索功能 。它允许用户通过 URL 查询参数(默认 search
)对多个字段进行模糊匹配。
一、基本用法
(1)启用 SearchFilter
默认情况下,ModelViewSet
并不会自动支持搜索功能,必须显式启用 SearchFilter
:
python
from rest_framework.viewsets import ModelViewSet
from rest_framework.filters import SearchFilter
from myapp.models import Dish
from myapp.serializers import DishSerializer
class DishViewSet(ModelViewSet):
"""菜品视图集"""
queryset = Dish.objects.all()
serializer_class = DishSerializer
# 启用搜索过滤器
filter_backends = [SearchFilter]
# 指定可以搜索的字段
search_fields = ['name', 'description', 'ingredients']
(2)基本查询
一旦启用了 SearchFilter
,就可以在请求 URL 里使用 search
参数:
GET /api/dishes/?search=spicy
这将在 name
、description
和 ingredients
字段中查找包含 "spicy"
的数据。
二、search_fields
语法
search_fields
支持多种匹配方式,包括:
- 模糊匹配(默认)
- 精确匹配
- 跨表搜索(ForeignKey、OneToOneField)
- 全文搜索(PostgreSQL
SearchVector
) - 多字段联合搜索
(1)模糊匹配(默认)
python
search_fields = ['name', 'description']
等价于:
sql
WHERE name ILIKE '%query%' OR description ILIKE '%query%'
- 忽略大小写
- 匹配部分内容
- 适用于
CharField
、TextField
,但对于IntegerField
或BooleanField
无效
示例 URL:
GET /api/dishes/?search=chicken
会在 name
和 description
字段里查找 "chicken" 相关的记录。
(2)精确匹配
如果希望进行精确匹配 ,可以在字段名前加 =
:
python
search_fields = ['=name']
等价于:
sql
WHERE name = 'query'
示例 URL:
GET /api/dishes/?search=Pizza
只会返回 name
完全等于 "Pizza"
的记录 ,不会匹配 "Pizza Hut"
或 "Spicy Pizza"
。
(3)前缀搜索
使用 ^
号可以进行前缀匹配:
python
search_fields = ['^name']
等价于:
sql
WHERE name ILIKE 'query%'
示例 URL:
GET /api/dishes/?search=Chi
会匹配 "Chicken Soup" 、"Chinese Noodles" ,但不会匹配 "Spicy Chicken"
。
(4)跨表搜索(ForeignKey、OneToOneField)
可以搜索关联模型的字段:
python
search_fields = ['category__name']
等价于:
sql
WHERE category.name ILIKE '%query%'
如果 Dish
模型的 category
是 ForeignKey
关联到 Category
模型:
python
class Category(models.Model):
name = models.CharField(max_length=100)
class Dish(models.Model):
name = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
示例 URL:
GET /api/dishes/?search=Asian
会返回所有 category.name
包含 "Asian"
的菜品。
(5)全文搜索(PostgreSQL)
如果使用 PostgreSQL,可以启用全文搜索:
python
from django.contrib.postgres.search import SearchVector
from rest_framework.filters import SearchFilter
class DishViewSet(ModelViewSet):
queryset = Dish.objects.all()
search_fields = ['name', 'description']
filter_backends = [SearchFilter]
def get_queryset(self):
query = self.request.query_params.get('search', None)
if query:
return Dish.objects.annotate(search=SearchVector('name', 'description')).filter(search=query)
return super().get_queryset()
- 比
ILIKE
更高效 - 支持
AND
、OR
逻辑 - 适用于大数据集
(6)多字段联合搜索
多个字段可用 ,
分隔:
python
search_fields = ['name', 'description', 'category__name']
示例 URL:
GET /api/dishes/?search=spicy
会在 name
、description
、category__name
三个字段中查找 "spicy"
。
三、配合 SearchFilter
进行优化
(1)增加 search_param
名称
默认 SearchFilter
使用 search
作为查询参数名,可以修改:
python
from rest_framework.filters import SearchFilter
class CustomSearchFilter(SearchFilter):
search_param = 'q' # 修改为 'q'
class DishViewSet(ModelViewSet):
filter_backends = [CustomSearchFilter]
search_fields = ['name', 'description']
示例 URL:
GET /api/dishes/?q=chicken
(2)与 OrderingFilter
结合
可以同时使用 OrderingFilter
进行排序:
python
from rest_framework.filters import SearchFilter, OrderingFilter
class DishViewSet(ModelViewSet):
filter_backends = [SearchFilter, OrderingFilter]
search_fields = ['name', 'description']
ordering_fields = ['price', 'preparation_time']
示例 URL:
GET /api/dishes/?search=spicy&ordering=-price
按照 price
降序排序(-price
表示降序)。
(3)与 DjangoFilterBackend
结合
可以同时支持精确筛选和模糊搜索:
python
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter
class DishViewSet(ModelViewSet):
filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ['category', 'is_vegetarian']
search_fields = ['name', 'description']
示例 URL:
GET /api/dishes/?search=pasta&category=italian
会:
- 在
name
和description
字段搜索"pasta"
- 过滤
category=italian
四、总结
功能 | 语法 | 作用 |
---|---|---|
模糊匹配 | search_fields = ['name', 'description'] |
查找字段包含关键字 |
精确匹配 | search_fields = ['=name'] |
只匹配完全相等的值 |
前缀搜索 | search_fields = ['^name'] |
匹配前缀 |
跨表搜索 | search_fields = ['category__name'] |
允许搜索外键字段 |
全文搜索 | PostgreSQL SearchVector |
适用于大数据量的高效搜索 |
修改参数名 | search_param = 'q' |
自定义搜索字段名 |
SearchFilter
适合小型数据集 的简单搜索,若数据量较大,建议使用Django Filter 或 全文搜索 (如 Elasticsearch、PostgreSQL SearchVector
)。