如何在Django ORM中不对'%'字符进行转义?
问题描述
使用Django ORM开发时,希望查询时不对字符%进行转义,但当前使用__contains生成的SQL会自动转义%为\%,不符合需求。
当前代码:
name='' author='' annotation = 'harry%magic%school' criterion_name = Q(name__contains=cleaned_data['name']) criterion_author = Q(author__contains=cleaned_data['author']) criterion_annotation = Q(annotation__contains=cleaned_data['annotation']) Book.objects.filter(criterion_name, criterion_author, criterion_annotation)
生成的SQL(不符合预期):
select name, author, annotation from books where name LIKE '%%' AND author LIKE '%%' AND annotation LIKE '%harry\%magic\%school%'
期望生成的SQL:
select name, author, annotation from books where name LIKE '%%' AND author LIKE '%%' AND annotation LIKE '%harry%magic%school%'
解决方法
Django的__contains会自动转义%和_(LIKE语法的通配符),把它们当作普通字符处理。如果你要让输入的%作为LIKE的通配符使用,有以下几种可行方案:
方案1:使用RawSQL直接构造LIKE条件
直接用RawSQL手动拼接LIKE语句,跳过Django的自动转义:
from django.db.models import RawSQL # 构造完整的LIKE匹配串,保留输入中的%作为通配符 annotation_pattern = f"%{cleaned_data['annotation']}%" Book.objects.filter( criterion_name, criterion_author, RawSQL("annotation LIKE %s", [annotation_pattern]) )
方案2:自定义Func实现LIKE查询
通过自定义Func类来构建未转义的LIKE表达式,更符合ORM的使用习惯:
from django.db.models import Func, Value class Like(Func): function = 'LIKE' template = "%(expressions)s %(function)s %(pattern)s" # 生成查询条件 criterion_annotation = Like('annotation', Value(f"%{cleaned_data['annotation']}%")) Book.objects.filter(criterion_name, criterion_author, criterion_annotation)
方案3:改用正则表达式查询(__regex)
如果可以接受用正则表达式替代LIKE,把输入中的%替换成正则的通配符.*:
# 将输入中的%替换为正则的任意字符匹配 regex_pattern = cleaned_data['annotation'].replace('%', '.*') criterion_annotation = Q(annotation__regex=regex_pattern) Book.objects.filter(criterion_name, criterion_author, criterion_annotation)
注意:这种方式生成的是REGEXP/RLIKE语句,和LIKE的匹配逻辑略有差异,性能也可能不同,需根据场景选择。
内容的提问来源于stack exchange,提问作者Olga
相关产品推荐
相关产品推荐

