Django ORM使用子查询按关键字搜索文本

Posted

技术标签:

【中文标题】Django ORM使用子查询按关键字搜索文本【英文标题】:Django ORM search in text by keywords with Subquery 【发布时间】:2018-10-16 08:48:48 【问题描述】:

我在 django 中有两个模型。具有字段标题的文章模型和具有字段标题的关键字模型。我需要对数据库进行查询并仅过滤那些标题包含关键字模型中任何关键字的文章。我尝试使用子查询进行搜索,但它不起作用。

如果我尝试filter id 与in 一起工作:

from django.db.models import Subquery

Article.objects.filter(id__in=Subquery(Keyword.objects.values('id')))

但如果我尝试使用icontainsfilter,它就不起作用了:

Article.objects.filter(title__icontains=Subquery(Keyword.objects.values('title')))

最后一个查询返回空查询集 如何解决?

【问题讨论】:

以上将为您提供包含所有关键字的Articles,并按特定顺序。 【参考方案1】:

最直接的方法是使用两个查询:一个查询获取所有Keywords,然后一个查询使用此关键字过滤Articles,例如:

from functools import reduce
from operator import or_

kws = Keyword.objects.values_list('title', flat=True)
articles = Article.objects.filter(
    reduce(or_, [Q(title__icontains=kw) for kw in kws])
)

但是,由于我们首先加载所有标题,因此上述内容可能会导致查询量很大。

另一种方法是使用.extra 创建JOIN,然后执行“原始”SQL 查询注释:

Article.objects.extra(
    tables=[Keyword._meta.db_table]
).annotate(
    key_title=RawSQL('.'.format(Keyword._meta.db_table, Keyword.title.field_name), ())
).filter(title__icontains=F('key_title'))

这将导致如下查询:

SELECT article.id, article.title, (keyword.title) AS key_title
FROM article , keyword
WHERE article.title LIKE CONCAT('%', REPLACE(REPLACE(REPLACE(((keyword.title)), '\\\\', '\\\\\\\\'), '%', '\\%'), '_', '\\_'), '%')

REPLACE(..) 部分用于转义关键字标题,因为如果它包含%,这可能会导致LIKE 表达式中出现“通配符”。这都是__icontains查找引入的,所以我们不用担心这个。

【讨论】:

太棒了。谢谢,这就是我一直在寻找的。它有效......我使用了一个额外的字符串,但我不知道如何在头部设计这样的结构。非常感谢。

以上是关于Django ORM使用子查询按关键字搜索文本的主要内容,如果未能解决你的问题,请参考以下文章

富文本关键字搜索高亮,解决方法及优化(收藏!)

如何使用子查询 django ORM?

django-模型层(ORM语法)

django-模型层(ORM语法)

在 Django 的 ORM 中使用带有 UPDATE 的子查询

使用Django ORM查询如何注释是不是存在多级外键层次结构