sqlalchemy绑定值

dre*_*obb 2 python sqlalchemy

我想动态地在sqlalchemy查询对象中获取paramer的值:

q = session.query(Model).filter(Model.foo = 6)
Run Code Online (Sandbox Code Playgroud)

我现在希望能够从q中检索值6

assert(q.magic == 6)
Run Code Online (Sandbox Code Playgroud)

尝试:打印q._criterion# - > models.foo =:foo_1但是foo_1的值在哪里?

Mar*_*ams 12

SQLAlchemy从过滤器谓词生成树结构,根据需要附加每个叶子并将结果放入Query._criterion.您可以使用get_children()各种类ClauseElementColumnElement类的方法来探索它.

因为Model.foo == 6你最终得到这样的东西:

                    Model.foo == 6        
                           |                 
                   _BinaryExpression
                          / \
                         /   \
                        /     \   
Column('foo', Integer(),      _BindParamClause(u'%(168261004 foo)s',
              ...)                             6, type_=Integer())  
Run Code Online (Sandbox Code Playgroud)

如果你和两个谓词一样,(Model.foo == 6) & (Model.name == 'a name')或者通过链接filter来电,你会得到一个BooleanClauseList有两个_BinaryExpression孩子的人.这意味着您无法对简单表达式进行硬编码以可靠地返回所需的值,而是必须遍历谓词树.

traverse从功能sqlalchemy.sql.visitors做到了这一点,靠的是涉及每个元素的特殊名字的字典__visit_name__属性的处理功能.这是一个广度优先的遍历,如您所见,适用于下面的示例; 还有深度优先版本.

以下函数显示如何从给定查询生成列参数对列表.我从Beaker缓存示例中对其进行调整:

 def extract_cols_params(query):
      if query._criterion is None:
           return []

      c, v = [], []

      def visit_bindparam(bind):
           value = query._params.get(bind.key, bind.value)
           if callable(value):
                value = value()
           v.append(value)

      def visit_column(col):
           c.append('%s.%s' % (col.table.name, col.name))

      visitors.traverse(query._criterion, # our predicate tree  
                        {}, # kwargs for the iterator used by
                            # the traversal; undeeded.
                        {'bindparam': visit_bindparam, # for _BindParamClauses
                         'column'   : visit_column})   # for Columns
      return zip(c, v)

>>> extract_cols_params(Session.query(Model).filter((Model.foo == 6)
    ).filter(Model.name == 'a name'))
[('models.foo', 6), ('models.name', 'a name')]
Run Code Online (Sandbox Code Playgroud)