You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Rest Framework中查询前去除搜索词重音的实现方法

在Django 1.9中去除搜索词重音的实现方案

针对你的需求,要在执行查询前去除搜索词的重音,结合你的现有配置,咱们一步步来解决:

1. 先写个通用的去重音工具函数

首先需要一个能把带重音的字符转成普通字符的函数,用Python的unicodedata模块就能实现:

import unicodedata

def remove_accents(input_str):
    # 把带重音的字符分解成「基础字符+重音标记」的组合
    nfkd_form = unicodedata.normalize('NFKD', input_str)
    # 过滤掉重音标记,只保留基础字符
    return "".join([c for c in nfkd_form if not unicodedata.combining(c)])

2. 自定义SearchFilter处理搜索词

Django REST Framework的默认SearchFilter不会处理重音,咱们需要重写它的get_search_terms方法,对用户输入的搜索词先做去重音处理:

from rest_framework.filters import SearchFilter

class AccentInsensitiveSearchFilter(SearchFilter):
    def get_search_terms(self, request):
        # 先拿到默认的搜索词列表
        terms = super().get_search_terms(request)
        # 给每个搜索词都做去重音处理
        return [remove_accents(term) for term in terms]

然后更新你的视图配置,把原来的SearchFilter换成咱们自定义的过滤器:

# 替换原filter_backends中的SearchFilter
filter_backends = (OrderingFilter, AccentInsensitiveSearchFilter)

3. 确保数据库能匹配无重音内容

只处理搜索词还不够,如果数据库里的name字段存的是带重音的内容,直接查询还是会匹配不到。这里给你两种可选方案:

方案A:保存时生成无重音字段(推荐,查询效率更高)

在模型里加一个不可编辑的字段,专门存无重音的名称,每次保存数据时自动生成:

class My_model(models.Model):
    class Meta:
        ordering = ['index']
    name = models.CharField(max_length=250, verbose_name="名称")
    # 新增无重名字段,设置为不可编辑
    name_unaccented = models.CharField(max_length=250, editable=False)
    
    def save(self, *args, **kwargs):
        # 保存前自动生成无重音版本的名称
        self.name_unaccented = remove_accents(self.name)
        super().save(*args, **kwargs)

然后更新视图的search_fields,改成搜索这个无重音字段:

search_fields = ('name_unaccented', )

方案B:查询时用数据库函数处理字段(适合无法修改模型的场景)

如果用的是PostgreSQL数据库,它内置了unaccent函数,可以直接在查询时对字段做去重音处理。咱们需要再重写过滤器的filter_queryset方法:

from django.db.models import Func, Q
from rest_framework.filters import SearchFilter

# 定义调用PostgreSQL unaccent函数的表达式
class Unaccent(Func):
    function = 'UNACCENT'
    template = "%(function)s(%(expressions)s)"

class AccentInsensitiveSearchFilter(SearchFilter):
    def get_search_terms(self, request):
        terms = super().get_search_terms(request)
        return [remove_accents(term) for term in terms]
    
    def filter_queryset(self, request, queryset, view):
        search_terms = self.get_search_terms(request)
        if not search_terms:
            return queryset
        
        search_fields = self.get_search_fields(view, request)
        if not search_fields:
            return queryset
        
        # 构造查询条件:同时匹配原字段和去重音后的字段
        conditions = []
        for term in search_terms:
            queries = []
            for field in search_fields:
                # 对数据库字段应用Unaccent函数,再匹配去重音后的搜索词
                queries.append(Q(**{f"{field}__icontains": term}))
                queries.append(Q(**{f"unaccent({field})__icontains": term}))
            conditions.append(Q(*queries))
        
        queryset = queryset.filter(*conditions)
        
        # 处理结果去重(如果需要)
        if self.must_call_distinct(queryset, view):
            queryset = queryset.distinct()
        
        return queryset

如果是MySQL等其他数据库,需要对应调整数据库函数的实现,比如用convert函数结合合适的编码来去除重音。

验证效果

现在当用户输入带重音的搜索词(比如café),过滤器会先转成cafe,再去匹配数据库中对应的无重音内容,就能得到正确的查询结果了。

内容的提问来源于stack exchange,提问作者Dannick Montanede

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:26:05