我正在寻找一种使用SQLAlchemy动态构造过滤器的方法。也就是说,给定该列,运算符名称和比较值,即可构造相应的过滤器。
我将尝试使用一个示例进行说明(这将用于构建API)。假设我们有以下模型:
class Cat(Model):
id = Column(Integer, primary_key=True)
name = Column(String)
age = Column(Integer)
我想将查询映射到过滤器。例如,
/cats?filter=age;eq;3
应该生成Cat.query.filter(Cat.age == 3)
/cats?filter=age;in;5,6,7&filter=id;ge;10
应该生成Cat.query.filter(Cat.age.in_([5, 6, 7])).filter(Cat.id >= 10)
我环顾四周,看看它是如何完成的,但是找不到一种不涉及手动将每个运算符名称映射到比较器或类似名称的方法。例如,Flask-Restless保留所有受支持操作的字典,并存储相应的lambda函数(code here)。
我在SQLAlchemy文档中进行了搜索,发现了两个潜在的线索,但似乎都不令人满意:
使用
Column.like
,Column.in_
...的getattr
变得简单,但仍然缺少某些运算符(==
,>
等)。 Column.op
的Cat.name.op('=')('Hobbes')
,但这似乎不适用于所有运算符(即in
)。 有没有
lambda
函数的干净方法吗? 最佳答案
如果这对某人有用,这就是我最终要做的事情:
from flask import request
class Parser(object):
sep = ';'
# ...
def filter_query(self, query):
model_class = self._get_model_class(query) # returns the query's Model
raw_filters = request.args.getlist('filter')
for raw in raw_filters:
try:
key, op, value = raw.split(self.sep, 3)
except ValueError:
raise APIError(400, 'Invalid filter: %s' % raw)
column = getattr(model_class, key, None)
if not column:
raise APIError(400, 'Invalid filter column: %s' % key)
if op == 'in':
filt = column.in_(value.split(','))
else:
try:
attr = filter(
lambda e: hasattr(column, e % op),
['%s', '%s_', '__%s__']
)[0] % op
except IndexError:
raise APIError(400, 'Invalid filter operator: %s' % op)
if value == 'null':
value = None
filt = getattr(column, attr)(value)
query = query.filter(filt)
return query
这涵盖了所有SQLAlchemy列比较器:
eq
for ==
lt
for <
ge
for >=
in
for in_
like
for like
带有相应名称的详尽列表可以在here中找到。
关于python - 在SQLAlchemy中动态构造过滤器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14845196/