在this问题解决了SQL中反向LIKE
操作的问题,例如,如果字段名称是“Peter Johnson”,我们可以通过这样的查询找到它:
select name from user where "Mr. Peter Johnson" like CONCAT('%', name, '%')
有没有办法在Django Q
对象中执行此类操作(我正在构建一个大查询,因此使用原始SQL查询将不合理)?
答案 0 :(得分:3)
不幸的是,Django的ORM没有任何内置的反向LIKE。但是.extra()
子句可能比原始查询更容易。
我使用过这样的东西:
qs.extra(
where=['''%s LIKE %s.%s'''],
params=(
"string to match",
FooModel._meta.db_table,
"bar_field",
),
)
上面代码的问题是
1)它不能以这种形式使用sqlite后端(“语法错误附近。”,它确实与查询中硬编码的表/列名一起使用...这并不总是安全且总是很难看);
和2)它要求FooModel.bar_field拥有数据%in like style%
,因此您无法匹配任意字符串(这可以通过%s LIKE CONCAT("%", %s.%s, "%")
等查询修复,但它会使其成为特定于DBMS的,这不好)。
反转LIKE本身可能适用于任何主要的DBMS,但我只在sqlite和postgres上测试过。
也许有人应该推广我的解决方案并创建一个可重复使用的,与DBMS无关的应用程序,其中包含用于此特定任务的特殊子类查询集/管理器/ Q对象...
答案 1 :(得分:2)
如果您使用的是最新版本的Django(1.10或更高版本)并使用Postgres,则ORM可以处理此问题。 Check out the docs.
trigram_similar
查询将为您提供所需内容:
qs = MyModel.objects.filter(name__trigram_similar='Mr. Peter Johnson')
不要忘记启用pg_tgrm扩展名来启用此查找。您可以使用django migration。
执行此操作您需要将'django.contrib.postgres'
添加到INSTALLED_APPS
设置中。
答案 2 :(得分:0)
尽管Extras确实为边缘情况提供了扩展的复杂功能,但Extras应该被视为万不得已,并且在某些时候可能会被弃用。
这可以通过注释和过滤来实现。
from django.db.models import F, Value, CharField
MyUserModel.objects \
.annotate(my_name_field=Value('Mr. Peter Johnson', output_field=CharField())) \
.filter(my_name_field__icontains=F('name'))
通用:
from django.db.models import F, Value, CharField
@staticmethod
def reverse_case_insensitive_contains(model, search_field_name: str, search_field_value: str):
return model.objects \
.annotate(search_field=Value(search_field_value, output_field=CharField())) \
.filter(search_field__icontains=F(search_field_name))
答案 3 :(得分:-2)
output = MyModel.objects.filter(Q(name__contains="Mr. Peter Johnson"))