2011-06-06 43 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')]