web-dev-qa-db-ja.com

文字列値を明示的に引用する方法(Python DB API / Psycopg2)

いくつかの理由で、2番目のパラメーターの内容に対してcursor.executeメソッドによって実行される暗黙的な引用を待つのではなく、文字列値の明示的な引用(構築されたSQLクエリの一部になる)を実行したいと思います。

「暗黙の引用」とは、次のことを意味します。

value = "Unsafe string"
query = "SELECT * FROM some_table WHERE some_char_field = %s;"
cursor.execute( query, (value,) ) # value will be correctly quoted

私はそのようなものを好むでしょう:

value = "Unsafe string"
query = "SELECT * FROM some_table WHERE some_char_field = %s;" % \
    READY_TO_USE_QUOTING_FUNCTION(value)
cursor.execute( query ) # value will be correctly quoted, too

そのような低レベルのREADY_TO_USE_QUOTING_FUNCTIONはPython DB API仕様で期待されています( PEP 249 ドキュメントでそのような機能を見つけることができませんでした)。そうでない場合は、おそらくPsycopg2そのような関数を提供しますか?そうでない場合は、おそらくDjangoはそのような関数を提供しますか?私はそのような関数を自分で作成したくないです...

27
Dariusz Walczak

さて、私は興味があったので、psycopg2のソースを調べました。実例フォルダより先に進む必要はなかったことがわかりました:)

はい、これはpsycopg2固有です。基本的に、文字列を引用したいだけの場合は、次のようにします。

from psycopg2.extensions import adapt

print adapt("Hello World'; DROP DATABASE World;")

しかし、おそらくやりたいことは、独自のアダプターを作成して登録することです。

Psycopg2のexamplesフォルダーには、ファイル 'myfirstrecipe.py' があります。特定のタイプを特別な方法でキャストおよび引用する方法の例があります。

やりたいことのオブジェクトがある場合は、「IPsycopgSQLQuote」プロトコルに準拠するアダプターを作成するだけです(myfirstrecipe.py-exampleについてはpydocsを参照してください...実際、その名前を見つけることができるのはそれだけです。 )オブジェクトを引用し、次のように登録します。

from psycopg2.extensions import register_adapter

register_adapter(mytype, myadapter)

また、他の例も興味深いものです。特に 'dialtone.py' および 'simple.py'

30

mogrify 関数を探していると思います。

例:

>>> cur.mogrify("INSERT INTO test (num, data) VALUES (%s, %s)", (42, 'bar'))
"INSERT INTO test (num, data) VALUES (42, E'bar')"
15
Beli

あなたはあなた自身の引用をすることを避けるように努めるべきです。人々が指摘しているように、それはDB固有であるだけでなく、引用の欠陥がSQLインジェクションのバグの原因です。

クエリと値を別々に渡したくない場合は、パラメータのリストを渡します。

def make_my_query():
    # ...
    return sql, (value1, value2)

def do_it():
    query = make_my_query()
    cursor.execute(*query)

(おそらくcursor.executeの構文が間違っています)ここでのポイントは、cursor.executeが多数の引数を取るからといって、それらすべてを個別に処理する必要があるという意味ではないということです。それらを1つのリストとして扱うことができます。

2
Ned Batchelder

私はあなたがこれを正しい方法で行うためにあなたの回避の背後にある十分な理由を与えているとは思わない。設計どおりにAPiを使用してください。次の人がコードを読みにくくし、壊れやすくするために、それほど努力しないでください。

1
ironfroggy

PyPika SQLステートメントを作成するための別の適切なオプション。使用例(プロジェクトのホームページの例に基づく):

>>> from pypika import Order, Query
>>> Query.from_('customers').select('id', 'fname', 'lname', 'phone').orderby('id', order=Order.desc)
SELECT "id","fname","lname","phone" FROM "customers" ORDER BY "id" DESC
0
asherbar

これはデータベースに依存します(iirc、mysqlはエスケープ文字として\を許可しますが、Oracleのようなものは引用符が2倍になることを期待します:'my '' quoted string')。

私が間違っていれば誰かが私を訂正しますが、二重引用法が標準的な方法です。

他のdb抽象化ライブラリ(sqlalchemy、cx_Oracle、sqliteなど)が何をするかを調べる価値があるかもしれません。

私は尋ねなければなりません-なぜあなたはそれらをバインドする代わりに値をインライン化したいのですか?

0

psycopg extension docs によると、コードスニペットは次のようになります。

_from psycopg2.extensions import adapt

value = "Unsafe string"
query = "SELECT * FROM some_table WHERE some_char_field = %s;" % \
    adapt(value).getquoted()
cursor.execute( query ) # value will be correctly quoted, too
_

getquoted関数は、引用符で囲まれたエスケープされた文字列としてvalueを返すため、"SELECT * FROM some_table WHERE some_char_field = " + adapt(value).getquoted()に移動することもできます。

0
Roberto

これはDBに依存します。たとえば、MySQLdbの場合、connectionクラスにはliteralメソッドがあり、MySQLに渡すために値を正しいエスケープ表現に変換します(これがcursor.execute使用)。

Postgresにも似たようなものがあると思いますが、DB API2.0仕様の一部として値をエスケープする機能はないと思います。

0
davidavr