2011-06-06 65 views
2

我希望得到一个paramer的动态一SQLAlchemy的查询对象的值:SQLAlchemy的绑定值

q = session.query(Model).filter(Model.foo = 6) 

我现在希望能够从q个

assert(q.magic == 6) 

尝试retrive值6 : print q._criterion# - > models.foo =:foo_1 但foo_1的值在哪里?

回答

12

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

Model.foo == 6你最终的东西是这样的:

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

如果你要&在一起的两个谓词,像(Model.foo == 6) & (Model.name == 'a name')或通过链接filter电话,你会得到一个BooleanClauseList有两个孩子_BinaryExpression 。这意味着你不能硬编码一个简单的表达式来可靠地返回你想要的值,而是必须遍历谓词树。

sqlalchemy.sql.visitorstraverse函数就是这样做的,它依赖于将每个元素的__visit_name__属性与处理函数相关联的特殊名称字典。这是一个宽度优先的遍历,正如你可以看到的,它适用于下面的例子。还有一个深度优先版本可用。

以下函数显示如何从给定查询生成列参数对的列表。我改编自the Beaker caching example

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')]