如何在Django API视图中实现西语特殊字符与标准字符的过滤兼容
实现支持西班牙语重音字符兼容过滤的Django API
要让你的API过滤器支持用无重音字符匹配带重音的字段值(比如用cancion匹配canción),可以通过以下两种方案实现:
方案一:利用数据库函数动态去重音(推荐,无额外存储)
1. 数据库准备(以PostgreSQL为例)
首先确保PostgreSQL安装了unaccent扩展,可通过迁移文件添加:
# 在你的app下创建迁移文件(比如0002_add_unaccent_extension.py) from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('your_app_name', '0001_initial'), # 替换为你的app最新迁移文件 ] operations = [ migrations.RunSQL('CREATE EXTENSION IF NOT EXISTS unaccent;'), ]
执行迁移:python manage.py migrate
2. 自定义FilterSet
创建支持去重音过滤的FilterSet,重写字段过滤逻辑:
from django_filters import rest_framework as filters from django.db.models import Func, Value from .models import Weeks # 定义调用数据库unaccent函数的Func类 class Unaccent(Func): function = 'UNACCENT' template = "%(function)s(%(expressions)s)" class OpenWeeksFilterSet(filters.FilterSet): activity = filters.CharFilter(method='filter_unaccented_field') discipline = filters.CharFilter(method='filter_unaccented_field') def filter_unaccented_field(self, queryset, name, value): # 对数据库字段和用户输入同时去重音,再做包含匹配 return queryset.annotate( unaccented_field=Unaccent(name) ).filter(unaccented_field__icontains=Unaccent(Value(value))) class Meta: model = Weeks fields = ['activity', 'discipline']
3. 更新API视图
将原视图的filterset_fields替换为自定义的filterset_class:
class OpenWeeksAPIView(generics.ListCreateAPIView): queryset = Weeks.objects.all() serializer_class = OpenWeeksSerializer filter_backends = [DjangoFilterBackend] filterset_class = OpenWeeksFilterSet # 替换原filterset_fields pagination_class = DefaultPagination
MySQL适配
如果使用MySQL,将Unaccent类替换为以下实现(依赖utf8mb4字符集):
class Unaccent(Func): function = 'CONVERT' template = "%(function)s(%(expressions)s USING utf8mb4) COLLATE utf8mb4_general_ci"
同时确保你的数据库表字符集为utf8mb4,排序规则为utf8mb4_general_ci(该规则会自动忽略重音差异)。
方案二:预生成无重音字段(跨数据库通用)
通过在模型中添加无重音字段,保存数据时自动生成,过滤时直接匹配该字段:
1. 修改模型
安装unidecode库:pip install unidecode,然后更新模型:
from django.db import models from unidecode import unidecode class Weeks(models.Model): activity = models.CharField(max_length=255) discipline = models.CharField(max_length=255) # 添加不可编辑的无重音字段 activity_unaccented = models.CharField(max_length=255, editable=False) discipline_unaccented = models.CharField(max_length=255, editable=False) def save(self, *args, **kwargs): # 保存时自动生成无重音版本 self.activity_unaccented = unidecode(self.activity) self.discipline_unaccented = unidecode(self.discipline) super().save(*args, **kwargs)
执行迁移:python manage.py makemigrations && python manage.py migrate
2. 配置FilterSet
class OpenWeeksFilterSet(filters.FilterSet): activity = filters.CharFilter(field_name='activity_unaccented', lookup_expr='icontains') discipline = filters.CharFilter(field_name='discipline_unaccented', lookup_expr='icontains') class Meta: model = Weeks fields = ['activity', 'discipline']
最后同样更新API视图的filterset_class即可。
内容的提问来源于stack exchange,提问作者Carlos S. C.
相关产品推荐
相关产品推荐

