如何在Django查询中使用正则表达式获取路径的最短匹配结果
解决方案
你的查询逻辑方向搞反了,__icontains是判断dir_id字段包含给定路径,实际你需要的是给定路径匹配dir_id的通配规则,再取最短的匹配即可。
方案1:用SQL LIKE实现(性能更好)
利用Postgres的REPLACE函数把dir_id里的*替换为SQL通配符%,再判断给定路径是否匹配该模式,最后按dir_id长度升序排序取第一条就是最短匹配:
from django.db.models import Func, F, Value, CharField, Length given_path = "Abcd/dir1/dir2" access_obj = Access.objects.annotate( dir_pattern=Func( F('dir_id'), Value('*'), Value('%'), function='REPLACE', output_field=CharField() ) ).filter( given_path__like=F('dir_pattern') ).order_by( Length('dir_id') ).first()
如果你的Django版本低于3.2,不支持filter左侧放常量,可以用extra实现:
given_path = "Abcd/dir1/dir2" access_obj = Access.objects.extra( where=['%s LIKE REPLACE(dir_id, \'*\', \'%\')'], params=[given_path] ).order_by('LENGTH(dir_id)').first()
方案2:用正则匹配实现
如果需要用正则的话,把dir_id里的*替换为正则通配符.*即可,逻辑和上面一致:
from django.db.models import Func, F, Value, CharField, Length given_path = "Abcd/dir1/dir2" access_obj = Access.objects.annotate( regex_pattern=Func( F('dir_id'), Value('*'), Value('.*'), function='REPLACE', output_field=CharField() ) ).filter( given_path__regex=F('regex_pattern') ).order_by( Length('dir_id') ).first()
内容的提问来源于stack exchange,提问作者Souvik Ray
相关产品推荐
相关产品推荐

