仅在 Django 查询中进行全字匹配

Posted

技术标签:

【中文标题】仅在 Django 查询中进行全字匹配【英文标题】:Whole-word match only in Django query 【发布时间】:2013-02-06 11:57:21 【问题描述】:

我正在尝试编写一个仅匹配整个单词的 Django 查询。根据here 的回答,我尝试过类似的方法:

result = Model.objects.filter(text__iregex='\bsomeWord\b')

但这并没有返回预期的结果。我也试过了

result = Model.objects.filter(text__iregex=r'\bsomeWord\b')

无济于事。我的最终目标是也能够传入一个字符串变量,例如:

result = Model.objects.filter(text__iregex=r'\b'+stringVariable+r'\b')

result = Model.objects.filter(text__iregex=r'\b %s \b'%stringVariable)

但现在我什至无法让它与原始字符串一起使用。我正在使用 PostgreSQL。

【问题讨论】:

【参考方案1】:

当你使用 PostgreSQL 时,使用“\y”而不是“\b”,这是因为 Django 将你的正则表达式直接传递给 PostgreSQL——所以你的RegEx 需要与之兼容。您应该可以从psql 执行它们而不会出现任何问题。

result = Model.objects.filter(text__iregex=r"\y0\y".format(stringVariable))

见https://www.postgresql.org/docs/9.1/functions-matching.html#POSIX-CONSTRAINT-ESCAPES-TABLE

【讨论】:

Django 不会将 PCRE 转换为 PostgreSQL 正则表达式(请参阅:bit.ly/ZtpbgH)。所以你只需要使用 PostgreSQL 的原生正则表达式,看这里:bit.ly/ZtpojU 这行得通。感谢您添加关于\y 的解释。至于'0'.format(stringVariable) 部分,这只是'%s'%stringVariable 的另一种写法吗?两者似乎都对我有用。 是的,实际上他们都做同样的事情。我只使用 .format() 方式,因为 Python 3 需要它 (python.org/dev/peps/pep-3101)。【参考方案2】:

你也许可以通过删除正则表达式并使用一些 django 查找来获得一些东西

result = Model.objects.filter(Q(text__contains=' someword ') |
                              Q(text__contains=' someword.') |
                              Q(text__istartswith = 'someword.' |
                              Q(text__istartswith = 'someword.' |
                              Q(text__iendswith = 'someword')

有关文档,请参阅 here。

我意识到这不是那么优雅(但如果您不是正则表达式的粉丝,那么维护起来很容易)。

【讨论】:

因为这不会执行全字匹配;例如,如果我执行text__contains='tart',我会选择start 这样的结果。 我的错 - 我显然对 sql 不够熟悉,无法知道“全词匹配”意味着特定的东西。无论如何,我已经更新了我的答案以改进它。 易于维护?有很多情况你没有涵盖(在()、逗号等之间)。 如果您不喜欢正则表达式,则易于维护。你不需要知道 django 或 python 来阅读这个 - 但我必须引用任何解决这个问题的正则表达式。是的,这并不能涵盖所有内容 - 只有当您确信文本仅包含该语言的一个子集时,它才会起作用。【参考方案3】:

我在尝试使用与 Perl 兼容的转义序列 \b 匹配单词边界时遇到了同样的问题。我的后端数据库是 mysql

我通过字符类表达式[[:space:]]解决了这个问题,例如

        q_sum = Q()
        search_list = self.form.cleaned_data['search_all'].split(' ');
        for search_item in search_list:
            search_regex = r"[[:space:]]%s[[:space:]]" % search_item
            q_sum |= Q(message__iregex=search_regex)
        queryset = BlogMessages.objects.filter(q_sum).distinct()

【讨论】:

这不包括标点符号。

以上是关于仅在 Django 查询中进行全字匹配的主要内容,如果未能解决你的问题,请参考以下文章

“ContentType 匹配查询不存在” - 仅在 SQLite 上,而不是 MySQL

Django模板仅在for循环中第一次出现匹配时执行

Django 通过匹配布尔值进行条件查询

django全文检索

Django REST EmailAddress 匹配查询不存在

Django - 匹配的查询不存在