使用 .contains() 的 SQLAlchemy 搜索太敏感

问题描述 投票:0回答:2

我有一个 Flask 应用程序,它有一个搜索栏,用户可以在数据库中搜索用户。这是代码:

users = []
for keyword in query.split():
  result = db.session.query(Users).filter(User.name.contains(keyword)).all()
  for user in result:
    users.append(user.name)

使用上面的示例,如果我要搜索“a”,那么名称中包含字母“a”的每个用户都会出现。如何搜索用户表,以便不再按字母搜索,而是按单词搜索?谢谢。

python search flask sqlalchemy flask-sqlalchemy
2个回答
3
投票

您可以将正则表达式与 SQLAlchemy 一起使用:

result = db.session.query(Users).filter(User.name.op('regexp')(r'\b{}\b'.format(keyword))).all()

匹配空字符串,但仅匹配单词的开头或结尾。单词被定义为字母数字或下划线字符的序列,因此单词的结尾由空格或非字母数字、非下划线字符指示。请注意,正式定义为 \w 和 \W 字符之间的边界(反之亦然),或者 \w 和字符串的开头/结尾之间的边界,因此被视为字母数字的字符的精确集合取决于UNICODE 和 LOCALE 标志的值。例如,r' foo ' 匹配 'foo'、'foo.'、'(foo)'、'bar foo baz',但不匹配 'foobar' 或 'foo3'。在字符范围内,表示退格字符,以与 Python 的字符串文字兼容。

https://docs.python.org/2/library/re.html


0
投票

Eugene Soldatovanswer 基本上是正确的:要在字符串中搜索单词,我们可以使用由包含在单词边界标记中的搜索词组成的正则表达式。然而,我们必须考虑到正则表达式的实现可能会根据所查询的 RDBMS 的不同而有所不同。

假设我们要查找包含单词“apple”的行,则使用的正则表达式为:

除了对正则表达式使用不同的语法之外,RDBMS 在用于匹配正则表达式的 SQL 语法方面也有所不同。 SQLAlchemy 提供了一个 regexp_match 方法,可以从 v1.4 开始抽象出这些差异:

term = 'apple'
select(Fruit.name).where(Fruit.name.regexp_match(fr'\b{term}\b'))

1 SQLite 不实现正则表达式,但提供了 SQLAlchemy 用来使用 Python 正则表达式引擎的钩子。

2 在 v8.0.4 之前使用的实现使用了第一个边界标记; v8.0.4 及更高版本使用

\b

3 在 v10.0.5 之前,MariaDB 使用第一个边界标记的 POSIX 兼容实现。 v10.0.5 使用支持

\b
的 PCRE 实现。

© www.soinside.com 2019 - 2024. All rights reserved.