我正在尝试使用 SQLAlchemy ORM 实现动态过滤。
我正在浏览 StackOverflow 并发现了非常相似的问题: SQLALchemy dynamic filter_by
这对我有用,但还不够。
所以,这里有一些代码示例,我正在尝试编写:
# engine - MySQL engine
session_maker = sessionmaker(bind=engine)
session = session_maker()
# my custom model
model = User
def get_query(session, filters):
if type(filters) == tuple:
query = session.query(model).filter(*filters)
elif type(filters) == dict:
query = session.query(model).filter(**filters)
return query
然后我试图用非常相似的东西重用它:
filters = (User.name == 'Johny')
get_query(s, filters) # it works just fine
filters = {'name': 'Johny'}
get_query(s, filters)
第二次运行后,出现了一些问题:
TypeError: filter() got an unexpected keyword argument 'name'
当我试图将我的 filters
更改为:
filters = {User.name: 'Johny'}
它返回:
TypeError: filter() keywords must be strings
但它适用于手动查询:
s.query(User).filter(User.name == 'Johny')
我的过滤器有什么问题?
顺便说一句,它看起来适用于以下情况:
filters = {'name':'Johny'}
s.query(User).filter_by(**filters)
但是根据上述帖子的建议,我尝试仅使用 filter
。
如果只能使用 filter_by
而不是 filter
,这两种方法之间有什么区别吗?
原文由 smart 发布,翻译遵循 CC BY-SA 4.0 许可协议
您的问题是 filter_by 采用关键字参数,但 filter 采用表达式。因此,为 filter_by **mydict 扩展字典将起作用。对于过滤器,您通常会向它传递一个参数,该参数恰好是一个表达式。因此,当您将 **filters dict 扩展到过滤器时,您向过滤器传递了一堆它不理解的关键字参数。
如果您想从存储的过滤器参数的字典中构建一组过滤器,您可以使用查询的生成特性来继续应用过滤器。例如:
上述模式的好处在于您可以在多个连接的列中使用它,您可以使用 and_ 和 or_ 构造“ands”和“ors”,您可以进行 <= 或日期比较,等等。它比使用带关键字的 filter_by 灵活得多。唯一需要注意的是,对于连接,您必须小心一点,不要不小心尝试连接一个表两次,并且您可能必须为复杂的过滤指定连接条件。我在一个非常复杂的域模型上使用它进行一些非常复杂的过滤,它就像一个魅力一样工作,我只是保持一个 entities_joined 的字典来跟踪连接。