バインド パラメータではなく、値を含むアプリケーションの有効な SQL を出力できるようにしたいのですが、SQLAlchemy でこれを行う方法が明確ではありません (設計によるものだと思います)。
この問題を一般的な方法で解決した人はいますか?
ベストアンサー1
ほとんどの場合、SQLAlchemy ステートメントまたはクエリの「文字列化」は次のように簡単です。
print(str(statement))
これは、ORMQuery
とselect()
その他のステートメントの両方に適用されます。
注:以下の詳細な回答は、sqlalchemy ドキュメント。
特定の方言またはエンジンにコンパイルされたステートメントを取得するには、ステートメント自体がまだバインドされていない場合は、これをコンパイル():
print(statement.compile(someengine))
またはエンジンなし:
from sqlalchemy.dialects import postgresql
print(statement.compile(dialect=postgresql.dialect()))
ORMオブジェクトが与えられた場合、メソッドにアクセスするQuery
には、compile()
。声明アクセサファースト:
statement = query.statement
print(statement.compile(someengine))
バインドされたパラメータは最終的な文字列に「インライン化」されるという当初の規定に関して、ここでの課題は、これは Python DBAPI によって適切に処理されるため、SQLAlchemy は通常これを実行しないということです。また、バインドされたパラメータをバイパスすることは、現代の Web アプリケーションで最も広く悪用されているセキュリティ ホールであることは言うまでもありません。SQLAlchemy は、DDL を発行する場合など、特定の状況でこの文字列化を行う能力が限られています。この機能にアクセスするには、次のものに渡される 'literal_binds' フラグを使用できますcompile_kwargs
。
from sqlalchemy.sql import table, column, select
t = table('t', column('x'))
s = select([t]).where(t.c.x == 5)
print(s.compile(compile_kwargs={"literal_binds": True}))
上記のアプローチには、int や文字列などの基本型に対してのみサポートされているという注意点があり、さらに、bindparam
事前設定された値のない が直接使用されると、それを文字列化することもできません。
サポートされていない型のインラインリテラルレンダリングをサポートするには、メソッドTypeDecorator
を含むターゲット型に を実装しますTypeDecorator.process_literal_param
。
from sqlalchemy import TypeDecorator, Integer
class MyFancyType(TypeDecorator):
impl = Integer
def process_literal_param(self, value, dialect):
return "my_fancy_formatting(%s)" % value
from sqlalchemy import Table, Column, MetaData
tab = Table('mytable', MetaData(), Column('x', MyFancyType()))
print(
tab.select().where(tab.c.x > 5).compile(
compile_kwargs={"literal_binds": True})
)
次のような出力が生成されます:
SELECT mytable.x
FROM mytable
WHERE mytable.x > my_fancy_formatting(5)