如何用Django高效查询PostgreSQL列中最后一个|后的内容
解决Django+PostgreSQL匹配最后一个|后文本的问题
为什么iendswith没结果?
大概率是这两个原因:
- 字段值最后一段前后藏着空白字符(比如换行、全角空格),导致
iendswith的精确结尾匹配失败 - 你误以为
iendswith会自动识别分隔符后的内容,但它其实是匹配整个字段的末尾,只有当searchTxt和字段最后一个字符完全对应(不区分大小写)才会命中
高效解决方案(PostgreSQL专属)
因为用的是PostgreSQL,直接用它的split_part函数提取最后一段内容,是最准确且能优化速度的方式:
1. 基础查询
先通过annotate提取最后一个|后的部分,再做不区分大小写的匹配:
from django.db.models import Func, F, Value # 提取最后一个|后的内容,再匹配 results = Mymodel.objects.annotate( last_segment=Func( F('name'), Value('|'), Value(-1), # split_part的第三个参数填-1表示取最后一段 function='split_part' ) ).filter(last_segment__iexact=searchTxt)
2. 提速:创建函数索引
如果数据量不小,为了让查询最快,给最后一段内容创建索引:
先在PostgreSQL里执行这条SQL创建索引:
CREATE INDEX idx_mymodel_last_segment ON mymodel (LOWER(split_part(name, '|', -1)));
然后修改查询语句,让它用上这个索引:
from django.db.models import Func, F, Value # 直接用LOWER后的结果匹配,触发索引 results = Mymodel.objects.filter( Func( Func( F('name'), Value('|'), Value(-1), function='split_part' ), function='LOWER' ) == searchTxt.lower() )
这样数据库会直接走索引,查询速度会快很多。
排查原方法失效的小技巧
如果非要用iendswith,先检查字段值和searchTxt的实际内容:
# 拿一条数据出来看真实内容 sample = Mymodel.objects.first() print(repr(sample.name)) # repr会显示所有隐藏字符,比如换行、空格 print(repr(searchTxt))
比如要是字段结尾带了换行符'XY Unit\n',而你的searchTxt是'XY Unit',肯定匹配不上,这时候可以先对字段做去空白处理后再用iendswith:
from django.db.models import Func, Value results = Mymodel.objects.filter( Func(F('name'), Value(' \t\n\r'), function='TRIM')__iendswith=searchTxt )
内容的提问来源于stack exchange,提问作者THADEUS ODHIAMBO LWANDE
相关产品推荐
相关产品推荐

