SQLAlchemy中能否嵌套自定义函数?自定义函数调用问题咨询
在SQLAlchemy中让自定义函数互相调用的正确方式
你遇到的问题本质是SQLAlchemy的自定义函数编译逻辑不会自动递归解析其他自定义函数的编译规则——当你在compile_my_func_2里用func.my_func_1(col)时,编译器只会把它当作一个普通的SQL函数引用,不会触发my_func_1对应的自定义编译函数,所以最终输出的是my_func_1("Start")而不是展开后的to_date调用。
解决方法:直接实例化自定义函数类
修改my_func_2的编译函数,把func.my_func_1(col)替换为直接实例化my_func_1类,这样编译器会自动找到对应的compile_my_func_1来处理它:
import sqlalchemy from sqlalchemy import func, column from sqlalchemy.ext.compiler import compiles from sqlalchemy.sql.functions import FunctionElement class my_func_1(FunctionElement): name = 'my_func_1' @compiles(my_func_1) def compile_my_func_1(element, compiler, **kw): col, = list(element.clauses) return compiler.process(func.to_date(col, 'dd-mm-yyyy'), **kw) class my_func_2(FunctionElement): name = 'my_func_2' @compiles(my_func_2) def compile_my_func_2(element, compiler, **kw): col, = list(element.clauses) # 直接实例化my_func_1,而不是用func.my_func_1 return compiler.process(my_func_1(col), **kw) print(sqlalchemy.select([(my_func_1(column("Start")))])) print(sqlalchemy.select([(my_func_2(column("Start")))]))
修改后的输出
运行这段代码后,输出会完全符合你的预期:
SELECT to_date("Start", :to_date_1) SELECT to_date("Start", :to_date_1)
原理说明
func.my_func_1是SQLAlchemy生成的一个函数代理,它不会主动关联你的自定义编译逻辑;而直接实例化my_func_1(col)会创建一个my_func_1类的实例,当编译器处理这个实例时,会自动匹配到你定义的compile_my_func_1函数,从而完成递归的编译展开。
如果你的场景更复杂(比如需要传递多个参数,或者想直接复用编译逻辑),也可以直接调用my_func_1的编译函数:
def compile_my_func_2(element, compiler, **kw): col, = list(element.clauses) return compile_my_func_1(my_func_1(col), compiler, **kw)
不过直接让编译器处理实例的方式更简洁,也更符合SQLAlchemy的扩展设计。
内容的提问来源于stack exchange,提问作者Pat Buxton
相关产品推荐
相关产品推荐

