pymysql: 给 sql 语句传递字典参数


pymysql 执行 sql 操作的最主要一个方法就是:cursor.execute(sql, *args)

它给了个这样的例子:

import pymysql.cursors

# Connect to the database
connection = pymysql.connect(host='localhost',
                             user='user',
                             password='passwd',
                             db='db',
                             charset='utf8mb4',
                             cursorclass=pymysql.cursors.DictCursor)

try:
    with connection.cursor() as cursor:
        # Create a new record
        sql = "INSERT INTO `users` (`email`, `password`) VALUES (%s, %s)"
        cursor.execute(sql, ('[email protected]', 'very-secret'))

    # connection is not autocommit by default. So you must commit to save
    # your changes.
    connection.commit()

    with connection.cursor() as cursor:
        # Read a single record
        sql = "SELECT `id`, `password` FROM `users` WHERE `email`=%s"
        cursor.execute(sql, ('[email protected]',))
        result = cursor.fetchone()
        print(result)
finally:
    connection.close()

语句写好了,里面可能有很多占位符 %s,但是数据参数,如果有很多,又要一个一个定好位置组成 tuple 再给它么?长期这么干最后总会心累的,能不能直接传 dict 给它呢?

答案当然是可以的,有人在 stackoverflow 上也问了这个问题,答案中还解答了关于数据库驱动的 paramstyle 问题,因为支持什么样的模式,完全看数据库驱动的实现方式了。

  • %s 这种占位符的,叫 format 模式,一般可以使用 %(name)s 这种格式来使用字典参数
  • ? 这种占位符的,叫 qmark 模式,一般会使用 :name 这种格式来使用字典参数,SQLAlchemy 看起来就是用的这种

还有一种叫 numeric 模式的,具体可以看下这个 paramstyle 的说明

查询数据库驱动支持什么样的,这里只看下 pymysql:

In[21]: import pymysql
In[22]: pymysql.paramstyle
Out[22]: 'pyformat'

以及,pymysql 也在 execute 文档中明确提到这么一句:

If args is a list or tuple, %s can be used as a placeholder in the query. If args is a dict, %(name)s can be used as a placeholder in the query.

这样,就能确定可以使用 %(name)s 这种格式来使用字典参数了:

params = {'limit': 10}
sql = 'select * from test limit %(limit)s'
cursor.execute(sql, params)