在这个问题中解决LIKE
了SQL中反向操作的问题,例如如果字段名称是“Peter Johnson”,我们可以通过这样的查询找到它:
select name from user where "Mr. Peter Johnson" like CONCAT('%', name, '%')
有没有办法在 DjangoQ
对象中做这样的事情(我正在构建一个大查询,所以使用原始 SQL 查询是不合理的)?
在这个问题中解决LIKE
了SQL中反向操作的问题,例如如果字段名称是“Peter Johnson”,我们可以通过这样的查询找到它:
select name from user where "Mr. Peter Johnson" like CONCAT('%', name, '%')
有没有办法在 DjangoQ
对象中做这样的事情(我正在构建一个大查询,所以使用原始 SQL 查询是不合理的)?
虽然附加功能确实为边缘情况提供了扩展的复杂功能,但附加功能应被视为最后的手段,并且可能会在某些时候被弃用。
这可以使用注释和过滤来完成。
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))
不幸的是,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,这不好)。
Reversed LIKE 本身可能适用于任何主要的 DBMS,但我只在 sqlite 和 postgres 上对其进行了测试。
也许有人应该概括我的解决方案并为这个特定任务创建一个具有特殊子类查询集/管理器/Q 对象的可重用、与 DBMS 无关的应用程序......
output = MyModel.objects.filter(Q(name__contains="Mr. Peter Johnson"))