如何将 Python 方法链接与另一个方法结合使用



我正在查询(通过sqllchemy(my_table对一列的条件,然后在另一列中检索不同的值。很简单

selection_1 = session.query(func.distinct(my_table.col2)).
filter(my_table.col1 == value1)

我需要反复执行此操作才能从my_table的不同列中获取不同的值。

selection_2 = session.query(func.distinct(my_table.col3)).
filter(my_table.col1 == value1).
filter(my_table.col2 == value2)
selection_3 = session.query(func.distinct(my_table.col4)).
filter(my_table.col1 == value1).
filter(my_table.col2 == value2).
filter(my_table.col3 == value3)

上面的代码有效,但由于我需要连续调用 6 次,它有点失控。我创建了一个类来处理方法链接:

class QueryProcessor:
def add_filter(self, my_table_col, value):
filter(my_table_col == value)
return self
def set_distinct_col(self, my_other_table_col):
self.my_other_table_col = my_other_table_col
return session.query(func.distinct(self.my_other_table_col))

理想情况下,我将能够像

selection_1 = QueryProcessor().set_distinct_col(my_table.col2).add_filter(my_table.col1, value1)
selection_2 = selection_1.set_distinct_col(my_table.col3).add_filter(my_table.col2, value2)
selection_3 = selection_2.set_distinct_col(my_table.col4).add_filter(my_table.col3, value3)

但是当我跑步时

selection_1 = QueryProcessor().set_distinct_col(my_table.col2).add_filter(my_table.col1, value1)

我收到以下错误:

Traceback (most recent call last):
File " ... "
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-20-789b26eccbc5>", line 10, in <module>
selection_1 = QueryProcessor().set_distinct_col(my_table.col2).add_filter(my_table.col1, value1)
AttributeError: 'Query' object has no attribute 'add_filter'

任何帮助将非常欢迎。

你真的不需要一个特殊的类。您现有的代码

selection_2 = session.query(func.distinct(my_table.col3)).
filter(my_table.col1 == value1).
filter(my_table.col2 == value2)

之所以有效,是因为filter基于原始查询返回一个新查询,但添加了额外的过滤器。您可以循环访问列及其相应的值,将每个旧查询替换为其后续查询。

selection2 = session.query(func.distinct(my_table.col3))
for col, val in zip([my_table.col1, my_table.col2], [value1, value2]):
selection2 = selection2.filter(col == val)
selection_3 = session.query(func.distinct(my_table.col4))
for col, val in zip([mytable.col1, mytable.col2, mytable.col3],
[value1, value2, value3]):
selection_3 = selection_3.filter(col == val)

也就是说,代码的问题在于add_filter实际上并没有调用查询的filter方法,也不会更新包装的查询。

class QueryProcessor:
def set_distinct_col(self, my_other_table_col):
self.query = session.query(func.distinct(self.my_other_table_col))
return self
def add_filter(self, my_table_col, value):
self.query = self.query.filter(my_table_col == value)
return self

但是,这会带来一个问题:set_distinct_col创建一个新查询,因此在以下内容中它实际上没有意义

selection_1 = QueryProcessor().set_distinct_col(my_table.col2).add_filter(my_table.col1, value1)
selection_2 = selection_1.set_distinct_col(my_table.col3).add_filter(my_table.col2, value2)
selection_3 = selection_2.set_distinct_col(my_table.col4).add_filter(my_table.col3, value3)

在现有实例上调用set_distinct_col。它可以返回新查询或现有查询,但不能同时返回两者(至少,如果要进行链接,则不能(。

另请注意,selection_1本身不是查询,而是selection_1.query

为了使add_filter()函数按预期工作,您需要set_distinct_col()函数返回对自身的引用(QueryProcessor的实例(。
session.query()返回一个没有add_filter()方法的Query对象。 如果您执行类似Query.add_filter = add_filter的操作,查询可以有一个add_filter方法,但这是一种不好的做法,因为它会修改 Query 类,所以我不建议这样做。

你正在做的是一个更好的选择。为了能够访问使用set_distinct_col()方法创建的查询,需要将其存储为实例变量。
下面,我通过将查询存储在实例变量中来完成此操作,queryself.query = session.query(func.distinct(self.my_other_table_col))

然后,我将add_filter()方法更改为返回自身,以允许链接更多 add_filter(( 方法。

class QueryProcessor:
def add_filter(self, my_table_col, value):
self.query = self.query.filter(my_table_col == value)
return self
def set_distinct_col(self, my_other_table_col):
self.my_other_table_col = my_other_table_col
self.query = session.query(func.distinct(self.my_other_table_col))
return self

您还应该知道,一次可以使用多个筛选条件,因此实际上不需要将多个筛选器链接在一起。

session.query(db.users).filter(or_(db.users.name=='Ryan', db.users.country=='England'))

session.query(db.users).filter((db.users.name=='Ryan') | (db.users.country=='England'))

SQLAlchemy 中筛选器和filter_by之间的区别

附言此代码尚未经过测试

最新更新