Django中如何通过SQL查询提取字段内指定分隔符后的子字符串
Django ORM 提取CharField分隔符后子内容的查询实现方案
核心实现思路
这类字符串提取逻辑优先下推到数据库层执行,避免将全量数据加载到Python内存做处理,大幅提升查询性能。核心逻辑分为两步:
- 定位分隔符
:在目标字段中的位置 - 从分隔符位置的下一位开始,截取到字符串末尾,得到需要的子内容
方案1:基于Django内置数据库函数实现(推荐,全数据库适配)
Django在django.db.models.functions模块中提供了通用的字符串处理函数,可自动适配MySQL、PostgreSQL、SQLite等所有支持的数据库,无需手写原生SQL。
代码实现
首先导入依赖模块:
from django.db.models import F from django.db.models.functions import Substr, Index
执行查询,将提取的子串作为额外字段返回:
# 定位字符串中冒号的位置 colon_pos = Index(F("str"), ":") queryset = model.objects.filter( # 先过滤出包含冒号的记录,避免无分隔符时截取逻辑异常 str__contains=":" ).annotate( # 给每条记录添加extracted_part属性,存储提取的目标子串 extracted_part=Substr( expression=F("str"), pos=colon_pos + 1 # 从冒号的下一个字符开始截取 ) ).all()
使用说明
- 返回的所有model实体都会附带
extracted_part属性,对应的值就是冒号后的子内容,例如原字段值为2021-22:32时,extracted_part值为32 - 生成的底层SQL等价于:
SELECT *, SUBSTRING(str, LOCATE(':', str) + 1) AS extracted_part FROM model_table WHERE str LIKE '%:%'
方案2:老版本Django兼容实现
如果使用的是Django 3.0以下的版本,没有内置Index函数,可以替换为兼容的Locate函数实现,逻辑完全一致:
from django.db.models import F from django.db.models.functions import Substr, Locate colon_pos = Locate(":", F("str")) # 定位冒号位置 queryset = model.objects.filter( str__contains=":" ).annotate( extracted_part=Substr( expression=F("str"), pos=colon_pos + 1 ) ).all()
注意事项
- 不推荐将全量数据查询到Python内存后循环做字符串切割处理,这种方式在数据量较大时会产生不必要的网络传输、内存占用开销
- 如果业务场景中存在多个连续冒号的格式异常数据,可以在过滤环节补充规则,排除无意义的记录
内容的提问来源于stack exchange,提问作者Sagar Agarwal
相关产品推荐
相关产品推荐

