python - 在 sqlalchemy 中动态生成过滤器,混合使用 and/or 和 not/like

标签 python sqlalchemy

我有一个定义了一些配置的字典,我不会提前知道我的用户想要构建的确切过滤器

它是这样指定的:

{"col1": ["val1", "~val2"],  
 "col2": ["val3", "val4"], 
 "col3": ["val5", "val6", "~val7", "~val8"]}

这应该翻译成:

WHERE ( 
  col1 LIKE val1 
  AND 
  col1 NOT LIKE val2 
) 
OR ( 
  col2 LIKE val3 
    OR 
  col2 LIKE val4 
) 
OR 
( 
  ( 
    col3 LIKE val5 
    OR 
    col3 LIKE val6 
  ) 
  AND 
    col3 NOT LIKE val7 
  AND 
    col3 NOT LIKE val8 
)

顶层的条件始终是“或”(您可以匹配指定的一列或匹配指定的另一列),而不是“和”

但是,在列表中,您可以匹配任何肯定条件,但不能匹配任何否定条件(此处的条件是字符串)

到目前为止,我动态构建这个的尝试看起来像这样:

def make_filter(definition):
    f = {}
    for variable in definition:
        v = getattr(Target, variable)
        f[v] = []
        for col in definition[variable]:
            f[v].append(col)
    return f


def make_query(def_dict):
    q = destination.query(Target)
    filter = make_filter(def_dict)
    for col in filter:
        for val in filter[col]:
            if '~' in val:
                q = q.filter(sa.not_(col.like(val)))
            else:
                q = q.filter(col.like(val))
    for record in q.all():
        # do stuff

但显然,这通过“和”组合了所有条件 - 我看不到一种在未知数量的条件下动态与“或”组合的方法......

只要可以明确指定同一组标准,如果这是解决此问题的更好方法,我可以修改规范。我没有特别要求用户将所有积极标准放在所有消极标准之前,但这是合理的。

最佳答案

考虑到上面提供的链接答案,不确定这是否应该被标记为欺骗 - 可能足够不同,仍然有帮助,所以以防万一我根据链接答案发布我的解决方案以确保完整性:

def make_filter(definition):
    f = {}
    for variable in definition:
        v = getattr(Target, variable)
        f[v] = {"like": [], "not": []}
        for col in definition[variable]:
            if "~" in col:
                f[v]["not"].append(re.sub('~', '', col))
            else:
                f[v]["like"].append(col)
    return f

def make_query(def_dict):
    q = destination.query(Target)
    filter = make_filter(def_dict)
    for item in filter:
        like_this = filter[item]["like"]
        not_this = filter[item]["not"]
        if len(not_this):
            for nt in not_this:
                q = q.filter(sa.not_(item.like(nt)))
        clauses = []
        for lt in like_this:
            clauses.append(item.like(lt))
        q = q.filter(sa.or_(*clauses))
        for record in q.all():
            # do stuff

关于python - 在 sqlalchemy 中动态生成过滤器,混合使用 and/or 和 not/like,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53095303/

相关文章:

python - Arrow 中的时间戳之间的差异

python - 如何获得查询结果的长度SqlAlchemy

python - 导入错误: No module named SQLAlchemy with Anaconda

python - 安排异步任务每 X 秒执行一次?

python - 将所有模块导入一个文件夹中,并通过其属性之一使用它们

python - 查找字典列表的所有排列

python - 使用 CBC 模式的 PyCrypto AES 256 加密 - 有什么弱点吗?

python - flask-login 仅在 get_id() 返回 self.email 时有效

mysql - 'sql_require_primary_key' - 在不创建主键的情况下无法将我的数据帧发送到 mysql 服务器

python - 我可以在查询调用中动态更改 order_by 属性吗?