Python SQLAlchemy查询的变量过滤器

Python SQLAlchemy查询的变量过滤器,python,sqlalchemy,Python,Sqlalchemy,我正在向我的应用程序(使用PyQt5创建)添加一个搜索功能,允许用户搜索数据库中的存档表。我提供了适用的字段,供用户选择匹配行。我在查询过滤器方面遇到了一些问题,因为其他字段都是空字符串,所以只能使用用户提供的内容 以下是我目前掌握的情况: def search_for_order(pierre): fields = {'archive.pat.firstname': pierre.search_firstname.text(), 'archive.pat.

我正在向我的应用程序(使用PyQt5创建)添加一个搜索功能,允许用户搜索数据库中的存档表。我提供了适用的字段,供用户选择匹配行。我在查询过滤器方面遇到了一些问题,因为其他字段都是空字符串,所以只能使用用户提供的内容

以下是我目前掌握的情况:

 def search_for_order(pierre):
    fields = {'archive.pat.firstname': pierre.search_firstname.text(),
              'archive.pat.lastname': pierre.search_lastname.text(),
              'archive.pat.address': pierre.search_address.text(),
              'archive.pat.phone': pierre.search_phone.text(),
              'archive.compound.compname': pierre.search_compname.text(),
              'archive.compound.compstrength': pierre.search_compstrength.text(),
              'archive.compound.compform': pierre.search_compform.currentText(),
              'archive.doc.lastname': pierre.search_doctor.text(),
              'archive.clinic.clinicname': pierre.search_clinic.text()
             }

    filters = {}

    for field, value in fields.items():
        if value is not '':
            filters[field] = value

     query = session.query(Archive).join(Patient, Prescribers, Clinic, Compound)\
             .filter(and_(field == value for field, value in filters.items())).all()

字段
字典收集搜索表单中所有字段的值。其中一些将为空,从而产生空字符串<代码>过滤器旨在成为对象名称和匹配值的字典。

一旦将查询对象绑定到SqlAlquemy中的表,即会话返回的内容。在上面的代码中,对该对象调用一些方法将返回一个新的、修改过的查询,已应用该筛选器的位置

因此,组合几个
过滤器的首选方法是从裸查询开始,迭代要使用的过滤器,然后为每个过滤器添加一个新的
。filter
调用并重新分配查询:

query = session.query(Archive).join(Patient, Prescribers, Clinic, Compound)
for field, value in filters.items():
    query = query.filter(field == value)
results = query.all()
按照您的意愿使用
也可以工作-在您的示例中,唯一缺少的是
*
。如果生成器表达式前面没有
*
,它将作为第一个(也是唯一的)参数传递给
。使用前缀
*
,迭代器中的所有元素都被解包到位,每个元素都作为参数传递:

...
.filter(and_(*(field == value for field, value in filters.items()))).all()

一旦在SqlAlquemy中获得一个绑定到表的查询对象(即,上面代码中的
session.query(Archive)
返回的内容),调用该对象上的某些方法将返回一个新的、修改过的查询,其中已经应用了该筛选器

因此,组合几个
过滤器的首选方法是从裸查询开始,迭代要使用的过滤器,然后为每个过滤器添加一个新的
。filter
调用并重新分配查询:

query = session.query(Archive).join(Patient, Prescribers, Clinic, Compound)
for field, value in filters.items():
    query = query.filter(field == value)
results = query.all()
按照您的意愿使用
也可以工作-在您的示例中,唯一缺少的是
*
。如果生成器表达式前面没有
*
,它将作为第一个(也是唯一的)参数传递给
。使用前缀
*
,迭代器中的所有元素都被解包到位,每个元素都作为参数传递:

...
.filter(and_(*(field == value for field, value in filters.items()))).all()

问题在于你对and_uu连接中表达式的定义。现在,您正在将每个字段与相应的值进行比较,当然,每次比较都返回false

为了正确地填充and_uu连接,您必须创建一个sqlalchemy称之为BinaryExpression对象的列表

为此,我将更改您的代码如下:

1) 首先在字段定义中使用对表类的实际引用:

2) 将筛选器定义为列表而不是字典:

filters = list()
3) 要填充过滤器列表,请分解字段字典中用作键的表和字段名的元组,并添加值以再次创建元组,但现在有三个元素。将每个新创建的元组追加到筛选器列表:

for table_field, value in fields.items():
    table, field = table_field
    if value:
        filters.append((table, field, value))
4) 现在,将创建的过滤器定义列表转换为sqlalchemy可用的BinaryExpression对象列表:

binary_expressions = [getattr(table, attribute) == value for table, attribute, value in filters]
5) 最后,将二进制表达式应用于查询,确保它以可使用的形式呈现给and_uu连接:

query = session.query(Archive).join(Patient, Prescribers, Clinic, Compound)\
         .filter(and_(*binary_expressions)).all()

我无法在您的配置中测试该解决方案,但使用我的环境进行的类似测试是成功的。

问题在于您对and_uu连接中表达式的定义。现在,您正在将每个字段与相应的值进行比较,当然,每次比较都返回false

为了正确地填充and_uu连接,您必须创建一个sqlalchemy称之为BinaryExpression对象的列表

为此,我将更改您的代码如下:

1) 首先在字段定义中使用对表类的实际引用:

2) 将筛选器定义为列表而不是字典:

filters = list()
3) 要填充过滤器列表,请分解字段字典中用作键的表和字段名的元组,并添加值以再次创建元组,但现在有三个元素。将每个新创建的元组追加到筛选器列表:

for table_field, value in fields.items():
    table, field = table_field
    if value:
        filters.append((table, field, value))
4) 现在,将创建的过滤器定义列表转换为sqlalchemy可用的BinaryExpression对象列表:

binary_expressions = [getattr(table, attribute) == value for table, attribute, value in filters]
5) 最后,将二进制表达式应用于查询,确保它以可使用的形式呈现给and_uu连接:

query = session.query(Archive).join(Patient, Prescribers, Clinic, Compound)\
         .filter(and_(*binary_expressions)).all()

我无法在您的配置中测试该解决方案,但使用我的环境进行的类似测试成功。

两个答案都在语句中生成
其中false=1
,导致一个空列表。只是开玩笑,语法错误。这似乎很有效,但我不完全理解为什么。你能具体说明你不理解的部分吗?我试图解释发生了什么,但显然这还不够。两个答案都在语句中生成
WHERE false=1
,结果是一个空列表。只是开玩笑,语法错误。这似乎很有效,但我不完全理解为什么。你能具体说明你不理解的部分吗?我试图解释发生了什么,但显然这还不够。这产生了一个WHERE子句
false=1
,我没有写过关于过滤器字典必须由从模型类中选择的真实字段对象组成的内容,另一个答案涉及到这一点。我想你在我写这个答案之前就知道了。这会产生一个WHERE子句,它的
false=1
我没有写过你的过滤器字典必须由从模型类中选择的实字段对象组成,另一个答案涉及到这一点。我想你在我写这个答案之前就知道了。