SQLAlchemy中的数据库函数命名参数
我在我的数据库(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)
我想在 Python 中也这样做,使用 SQLAlchemy 的 func
结构,但是看起来 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 个回答
4
感谢Michael Bayer的建议,我找到了自己问题的解决办法:诀窍在于使用SQLAlchemy的编译器,以及一些正确的转义处理:
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())