【后端】【Django】【ORM】SearchFilter 详解

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

这将在 namedescriptioningredients 字段中查找包含 "spicy" 的数据。


二、search_fields 语法

search_fields 支持多种匹配方式,包括:

  • 模糊匹配(默认)
  • 精确匹配
  • 跨表搜索(ForeignKey、OneToOneField)
  • 全文搜索(PostgreSQL SearchVector
  • 多字段联合搜索

(1)模糊匹配(默认)

python 复制代码
search_fields = ['name', 'description']

等价于:

sql 复制代码
WHERE name ILIKE '%query%' OR description ILIKE '%query%'
  • 忽略大小写
  • 匹配部分内容
  • 适用于 CharFieldTextField ,但对于 IntegerFieldBooleanField 无效

示例 URL:

复制代码
GET /api/dishes/?search=chicken

会在 namedescription 字段里查找 "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 模型的 categoryForeignKey 关联到 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 更高效
  • 支持 ANDOR 逻辑
  • 适用于大数据集

(6)多字段联合搜索

多个字段可用 , 分隔:

python 复制代码
search_fields = ['name', 'description', 'category__name']

示例 URL:

复制代码
GET /api/dishes/?search=spicy

会在 namedescriptioncategory__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

会:

  • namedescription 字段搜索 "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)。

相关推荐
robottt6661 小时前
2026国产协作机器人排名与选型指南:越疆、遨博、节卡、珞石解析
大数据·数据库·人工智能
郑州光合科技余经理2 小时前
本地生活系统:多业务订单字段怎么分账本导出
java·开发语言·前端·数据库·uni-app·php·ai编程
weixin_460443564 小时前
考试监控大屏为什么不能直接查数据库?WebSocket、Redis与实时数据聚合架构设计
数据库·redis·在线考试系统·培训考试系统·煤矿培训考试系统·煤矿在线考试系统·宏远培训考试系统
风哥2号5 小时前
数据库教程FGMT02‑生产环境Linux+Oracle19c安装配置与项目实战
linux·数据库·ffmpeg
九皇叔叔9 小时前
【第二章】Redis基础入门:Redis是什么、为什么快以及核心特性详解
数据库·redis·缓存
云和恩墨9 小时前
删库不跑路,回滚极速触达——zData S“旁路日志”持续保护原理深剖
数据库
MetaLite9 小时前
SpringBoot接口分层规范-外网网关内部服务与参数边界
java·数据库·spring boot
Wang's Blog11 小时前
Java框架快速入门: Spring Security+OAuth2之元注解简化权限表达式
java·数据库·spring
蓝速科技13 小时前
医院导诊 AI 数字人一体机场景适配与落地指南丨蓝速科技
运维·数据库·人工智能·科技·自然语言处理·技术分享
QYR-分析13 小时前
重轨受电弓行业深度报告:市场格局、技术迭代与发展前景
大数据·数据库·人工智能