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
相关产品推荐
相关产品推荐

