Django ORM搭配PostgreSQL使用icontains返回错误数据如何解决
问题根因
该异常是Ubuntu环境下PostgreSQL数据库的默认排序规则(collation)对西里尔字母的大小写映射处理异常导致的。Windows版本PostgreSQL的默认排序规则对西里尔字符的大小写不敏感匹配兼容性更好,因此本地运行无异常,Ubuntu默认的en_US.UTF-8或C.UTF-8排序规则未正确适配俄语字符的大小写判断,导致icontains查询结果错误。
解决步骤
1. 安装俄语语言包
Ubuntu系统默认未预装俄语locale,先执行命令安装:
sudo locale-gen ru_RU.UTF-8 sudo update-locale
安装完成后执行locale -a确认输出中存在ru_RU.utf8即为安装成功。
2. 修改字段排序规则(推荐方案,无需修改整库配置)
Django 3.2及以上版本支持直接在模型字段指定排序规则,修改Seller模型如下:
from django.db import models class Seller(models.Model): supplierId = models.IntegerField('Supplier ID', primary_key=True) supplierName = models.CharField( 'Поставщик', max_length=255, null=True, blank=True, # 指定适配俄语的排序规则 db_collation='ru_RU.UTF-8' ) inn = models.CharField('ИНН', max_length=255, null=True, blank=True) ogrn = models.CharField('ОГРН', max_length=255, null=True, blank=True) legalAddress = models.CharField('Юридический адрес', max_length=512, null=True, blank=True)
修改完成后执行python manage.py makemigrations、python manage.py migrate生成迁移并执行,即可更新字段的排序规则。
低版本Django可直接执行SQL修改字段配置:
ALTER TABLE 你的Seller表名 ALTER COLUMN supplierName TYPE varchar(255) COLLATE "ru_RU.UTF-8";
3. 临时兼容方案(无需修改数据库配置)
如果不想改动数据库结构,可在查询时手动统一转小写后匹配,绕过默认排序规则的限制:
from django.db.models.functions import Lower target_str = 'Смирнова Ольга Александровна' sellers = Seller.objects.annotate( lower_supplier_name = Lower('supplierName') ).filter(lower_supplier_name__contains = target_str.lower())
4. 全局生效方案(适用于全库都是俄语数据的场景)
如果整个库都以俄语数据为主,可重新创建数据库时指定全局排序规则:
CREATE DATABASE 你的数据库名 WITH ENCODING 'UTF8' LC_COLLATE='ru_RU.UTF-8' LC_CTYPE='ru_RU.UTF-8' TEMPLATE template0;
重新导入数据后所有查询默认适配俄语字符规则。
修改完成后icontains、__search等查询均可返回正确结果。
内容的提问来源于stack exchange,提问作者Фёдор Яковлев
相关产品推荐
相关产品推荐

