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

Django+PostgreSQL实现忽略重音的名称匹配搜索方案问询

Django+PostgreSQL重音不敏感搜索实现方案

一、先启用PostgreSQL的unaccent扩展

PostgreSQL的unaccent扩展是实现重音忽略搜索的核心,它能去除字符串中的重音标记。首先在数据库中执行以下SQL:

CREATE EXTENSION IF NOT EXISTS unaccent;

也可以通过Django迁移自动完成:创建空迁移文件(python manage.py makemigrations --empty your_app),然后在迁移文件中添加RunSQL操作:

from django.db import migrations

class Migration(migrations.Migration):
    dependencies = [
        ('your_app', '00xx_previous_migration'),
    ]

    operations = [
        migrations.RunSQL('CREATE EXTENSION IF NOT EXISTS unaccent;'),
    ]

执行python manage.py migrate完成扩展安装。

二、修改搜索逻辑代码

原代码使用__icontains匹配,无法忽略重音。需要通过Django的Func类调用unaccent,同时对字段值和搜索词去重音后再做匹配。修改后的代码如下:

from django.db.models import Func, Value, Q
from django.http import HttpResponse
from django.apps import apps
import json

def autocomplete(request):
    result = []
    try:
        if request.user.is_staff and request.user.is_active:
            columns = request.GET.get("column_name").split(",")
            value = request.GET.get("column_value")
            term = request.GET.get("term")
            
            # 构造重音不敏感的OR匹配条件
            q_objects = Q()
            for column in columns:
                # 对字段和搜索词都应用unaccent处理
                unaccent_field = Func(column, function='unaccent', output_field=models.CharField())
                unaccent_term = Func(Value(term), function='unaccent', output_field=models.CharField())
                q_objects |= Q(**{f'{unaccent_field}__icontains': unaccent_term})
            
            # 处理额外过滤条件
            filter_q = Q()
            filters = request.GET.get("filters", [])
            if filters:
                for f in filters.split(","):
                    key, val = f.split("=")
                    filter_q &= Q(**{key: val})
            
            # 替换自定义Filter为模型原生查询(若Filter支持Q对象,可直接传入q_objects)
            model = apps.get_model(
                app_label=request.GET.get("app_label"),
                model_name=request.GET.get("model")
            )
            queryset = model.objects.filter(q_objects & filter_q)
            
            for q in queryset:
                result.append(
                    {"obj": q.to_json(), "label": str(q), "value": q.to_json()[value]}
                )
    except AttributeError:
        pass
    return HttpResponse(json.dumps(result, cls=Codec), content_type="application/json")

代码说明:

  • 用Func包装字段和搜索词,调用PostgreSQL的unaccent去除重音
  • 通过Q对象实现多字段的OR匹配逻辑,对应原代码的operator.or_
  • 若你的自定义Filter类支持接收Q对象,可直接将q_objects传入filter_by_list,无需替换为模型原生查询

三、性能优化建议

  • 创建unaccent索引:对高频搜索字段创建基于unaccent的索引,提升模糊匹配速度:
    -- 先安装pg_trgm扩展(支持模糊匹配索引)
    CREATE EXTENSION IF NOT EXISTS pg_trgm;
    -- 创建Users表name字段的unaccent索引
    CREATE INDEX idx_users_name_unaccent ON users USING gin (unaccent(name) gin_trgm_ops);
    
  • 预处理搜索词:可在前端或后端用unidecode库提前对用户输入去重音,减少数据库计算,但后端仍需保留unaccent处理以保证数据准确性
  • 可选:使用CIText字段:若需同时实现大小写+重音不敏感,可将字段改为django.contrib.postgres.fields.CITextField,配合unaccent使用(需先安装citext扩展)

四、注意事项

  • 确保Django版本≥1.8(支持Func类)
  • 若自定义Filter有特殊业务逻辑,需调整其filter_by_list方法以兼容unaccent条件

内容的提问来源于stack exchange,提问作者holman rugama

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 11:45:08