我在我的应用程序中添加搜索功能(使用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()
fields
字典收集搜索表单中所有字段的值。其中一些将是空白的,导致空字符串。 filters
旨在成为对象名称的字典以及与之匹配的值。
答案 0 :(得分:3)
问题在于您在和_ 连接中定义表达式。截至目前,您将每个字段与相应的值进行比较,当然每次比较都会返回false。
要正确填充和_ 连接,您必须创建sqlalchemy调用 BinaryExpression 对象的列表。
为了做到这一点,我改变了你的代码:
1)首先在 fields 的定义中使用对表类的实际引用:
fields = {
(Patient, 'firstname'): pierre.search_firstname.text(),
(Patient, 'lastname'): pierre.search_lastname.text(),
(Patient, 'address'): pierre.search_address.text(),
(Patient, 'phone'): pierre.search_phone.text(),
(Compound, 'compname'): pierre.search_compname.text(),
(Compound, 'compstrength'): pierre.search_compstrength.text(),
(Compound, 'compform'): pierre.search_compform.currentText(),
(Prescribers, 'lastname'): pierre.search_doctor.text(),
(Clinic, 'clinicname'): pierre.search_clinic.text()
}
2)将过滤器定义为列表而不是字典:
filters = list()
3)填充过滤器列表会爆炸在 fields 字典中用作键的表和字段名的元组,并添加该值以再次创建元组,但现在有三个元素。将每个新创建的元组附加到过滤器列表中:
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)最后将二进制表达式应用于您的查询,确保它以可使用的形式呈现给和_ 连词:
query = session.query(Archive).join(Patient, Prescribers, Clinic, Compound)\
.filter(and_(*binary_expressions)).all()
我无法在您的配置中测试该解决方案,但使用我的环境进行的类似测试是成功的。
答案 1 :(得分:0)
一旦你得到一个绑定到SqlAlquemy中的表的查询对象 - 也就是上面代码中的session.query(Archive)
返回的内容 - ,调用该对象上的一些方法将返回一个新的,修改过的查询,其中过滤器已经应用。
因此,我首选合并多个and
过滤器的方法是从裸查询开始,遍历要使用的过滤器,并为每个过滤器添加新的.filter
调用并重新分配查询:
query = session.query(Archive).join(Patient, Prescribers, Clinic, Compound)
for field, value in filters.items():
query = query.filter(field == value)
results = query.all()
根据您的意图使用and_
或or_
也可以正常工作 - 就您的示例而言,唯一缺少的是*
。在生成器表达式之前没有*
,它将作为第一个(和唯一)参数传递给and_
。使用带前缀的*
,迭代器中的所有元素都会被解压缩,每个元素作为参数传递:
...
.filter(and_(*(field == value for field, value in filters.items()))).all()