使用SQLAlchemy在数据库函数中命名参数

时间:2013-03-08 12:00:21

标签: python function postgresql sqlalchemy named-parameters

我的数据库(Postgres)中有一个函数,如下所示:

create function test_f(a text default '*', b text default '+') returns text as $$
    select a || ' ' || b;
$$ language sql;

Postgres允许使用命名参数调用它:

mytest=> select test_f('a', 'b');                                           
test_f                                                                      
--------                                                                    
a b                                                                         
(1 row)                                                                     

mytest=> select test_f('a');                                                
test_f                                                                      
--------                                                                    
a +                                                                         
(1 row)                                                                     

mytest=> select test_f(b:='a');                                             
test_f                                                                      
--------                                                                    
* a                                                                         
(1 row)                                                                     

我想使用SQLAlchemy's func construct从Python做同样的事情,但似乎func不尊重命名参数:

In [85]: print(sqlalchemy.func.test_f('a', 'b'))                            
test_f(:test_f_1, :test_f_2)                                                

In [86]: print(sqlalchemy.func.test_f('a'))                                 
test_f(:test_f_1)                                                           

In [87]: print(sqlalchemy.func.test_f(a='a'))                               
test_f()                                                                    

我遗漏了什么,或func不支持命名参数?

1 个答案:

答案 0 :(得分:3)

感谢suggestion of Michael Bayer,我想出了一个解决我自己问题的方法:诀窍是使用SQLAlchemy's compiler,以及一些正确的转义:

from psycopg2.extensions import adapt as sqlescape                          
import sqlalchemy                                                           
from sqlalchemy import select                                               
from sqlalchemy.ext.compiler import compiles                                
from sqlalchemy.sql.expression import ColumnClause                          


class MyFunc(ColumnClause):                                                 
    def __init__(self, *args, **kwargs):                                    
        self.kwargs = kwargs                                                
        super().__init__(*args)                                             


@compiles(MyFunc)                                                           
def compile_myfunc(element, compiler, **kw):                                
    s = ','.join("%s:=%s" % (k, sqlescape(v)) for k, v in element.kwargs.items())
    return "%s(%s)" % (element.name, s)                                     


def call(engine, func, **kwargs):                                           
    return engine.execute(select([MyFunc(func, **kwargs)]))                 


engine = sqlalchemy.create_engine('postgresql+psycopg2://lbolla@localhost/mytest')
print(call(engine, 'test_f', a='a').scalar())                               
print(call(engine, 'test_f', b='b').scalar())