sqlite 如何创建动态过滤器?

tkqqtvp1  于 2022-11-14  发布在  SQLite
关注(0)|答案(5)|浏览(288)

我有一张有设备的table,每一张都有维护级别的日期。用户可以选择维护级别。因此,我应该针对所选择的每种维护级别组合调整我的SQLAlChemy。例如:

SELECT * WHERE (equipment IN []) AND m_level1 = DATE AND m_level2 = DATE ....)

因此,可以为每个if条件提供组合,这取决于我使用多个字符串来实现目标的复选框,但我希望使用SQLAlChemy改进查询。

kr98yfug

kr98yfug1#

我假设您正在使用ORM。
在这种情况下,filter函数返回一个查询对象。您可以通过执行如下操作来有条件地构建查询

query = Session.query(schema.Object).filter_by(attribute=value)
if condition:
    query = query.filter_by(condition_attr=condition_val)
if another_condition:
    query = query.filter_by(another=another_val)

#then finally execute it

results = query.all()
ykejflvf

ykejflvf2#

函数filter(*criterion)表示您可以使用元组作为其参数,@Wolph有详细信息:SQLALchemy dynamic filter_by表示详细信息

tp5buhyn

tp5buhyn3#

如果我们谈到SQLAlChemy核心,还有另一种方法:

from sqlalchemy import and_

filters = [table.c.col1 == filter1, table.c.col2 > filter2]
query = table.select().where(and_(*filters))

如果您尝试根据传入表单条件进行筛选:

form = request.form.to_dict()
filters = []
for col in form:
    sqlalchemybinaryexpression = (getattr(MODEL, col) == form[col])
    filters.append(sqlalchemybinaryexpression)
query = table.select().where(and_(*filters))

其中MODEL是您的SQLAlChemy模型

pkbketx9

pkbketx94#

这个问题的另一个解决方案是以一种更安全的方式提出这种情况,因为它验证要过滤的字段是否存在于模型中。
若要向要筛选的值添加运算符,请执行以下操作。并且不必向查询添加新参数,我们可以在值之前添加运算符,例如,?foo=>1,‘?foo=<1,?foo=>=1 ,?foo=<=1’,?foo=!1?foo=1,最后它们之间将类似于`?foo=a,b‘。

from sqlalchemy.orm import class_mapper
import re

# input parameters
filter_by = {
  "column1": "!1", # not equal to
  "column2": "1",   # equal to
  "column3": ">1",  # great to. etc...
}

def computed_operator(column, v):
  if re.match(r"^!", v):
    """__ne__"""
    val = re.sub(r"!", "", v)
    return column.__ne__(val)
  if re.match(r">(?!=)", v):
    """__gt__"""
    val = re.sub(r">(?!=)", "", v)
    return column.__gt__(val)
  if re.match(r"<(?!=)", v):
    """__lt__"""
    val = re.sub(r"<(?!=)", "", v)
    return column.__lt__(val)
  if re.match(r">=", v):
    """__ge__"""
    val = re.sub(r">=", "", v)
    return column.__ge__(val)
  if re.match(r"<=", v):
    """__le__"""
    val = re.sub(r"<=", "", v)
    return column.__le__(val)
  if re.match(r"(\w*),(\w*)", v):
    """between"""
    a, b = re.split(r",", v)
    return column.between(a, b)
  """ default __eq__ """
  return column.__eq__(v)

query = Table.query
filters = []
for k, v in filter_by.items():
  mapper = class_mapper(Table)
  if not hasattr(mapper.columns, k):
    continue
  filters.append(computed_operator(mapper.columns[k], "{}".format(v))
query = query.filter(*filters)
query.all()
jrcvhitl

jrcvhitl5#

这是一个既适用于AND也适用于OR的解决方案。
如果需要,只需将代码中的or_替换为and_

from sqlalchemy import or_, and_

my_filters = set() ## <-- use a set to contain only unique values, avoid duplicates

if condition_1:
    my_filters.add(MySQLClass.id == some_id)
if condition_2:
    my_filters.add(MySQLClass.name == some_name)

fetched = db_session.execute(select(MySQLClass).where(or_(*my_filters))).scalars().all()

相关问题