文字列フォーマット操作とDB-API 2.0は共存可能

Pythonsqlite3モジュールは大変に便利で、もはやなくなると困るくらいなのですが、これでSQLコマンドを実行する際には、インジェクションなどの危険を避ける目的でDB-API 2.0仕様に準拠したSQLインターフェイスを利用するようにしたほうが、なにかと無難で安全です。

DB-APIってのは、ConnectionオブジェクトのCursorオブジェクトに対し、SQLを実行しようという際に、変数に代入されている値(ユーザーの入力したものであることも多いでしょう)を安全に利用するための仕組みです。たとえば、変数を文字列フォーマット操作を使ってSQLに挿入すると、引用符などによってエラーが引き起こさたりすることがあります。さらに、SQLのコマンドなどを埋め込まれて、望ましくない操作がなされたりすることもあるかも。だから、DB-APIを使いましょうという話なんです。

でも、DB-APIではうまくいかないこともあります。たとえばORDER BY句などでレコードの並びを指定したい場合、フィールド名をDB-APIの?を使って指定しても反映されません。だから、文字列フォーマット操作を使うのですが、そうするとDB-API の書き方は使えないのかな。と疑問に思ったので、試してみたら、問題なく使えました。

こんな風に書いたらいけました。

import sqlite3

order = ['date ASC', 'price DESC']
price = 2000

conn = sqlite3.connect('/tmp/example')
c = conn.cursor()
c.execute('select * \
from table \
where price >= ? \
order by %s;' % ', '.join(order), \
              (price, ))
conn.close()

execute()メソッドの第1引数は文字列フォーマット操作までを含めたSQL文、第2引数は値を含むタプル。考えれば、別におかしくもない、シンプルな話でした。