使用Psycopg2插入Python字典
将包含多个键的Python字典插入Postgres数据库而不必枚举所有键的最佳方法是什么 我想做一些像使用Psycopg2插入Python字典,python,postgresql,psycopg2,Python,Postgresql,Psycopg2,将包含多个键的Python字典插入Postgres数据库而不必枚举所有键的最佳方法是什么 我想做一些像 song = dict() song['title'] = 'song 1' song['artist'] = 'artist 1' ... cursor.execute('INSERT INTO song_table (song.keys()) VALUES (song)') 应该采取以下措施: song = dict() song['title'] = 'song 1' song['a
song = dict()
song['title'] = 'song 1'
song['artist'] = 'artist 1'
...
cursor.execute('INSERT INTO song_table (song.keys()) VALUES (song)')
应该采取以下措施:
song = dict()
song['title'] = 'song 1'
song['artist'] = 'artist 1'
cols=song.keys();
vals = [song[x] for x in cols]
vals_str_list = ["%s"] * len(vals)
vals_str = ", ".join(vals_str_list)
cursor.execute("INSERT INTO song_table ({cols}) VALUES ({vals_str})".format(
cols = cols, vals_str = vals_str), vals)
关键部分是生成的%s
元素字符串,并以格式使用该字符串,将列表直接传递给execute
调用,以便psycopg2可以插入vals
列表中的每个项(从而防止可能的SQL注入)
另一种变体是将dict
传递给execute
,将使用这些行而不是上面的vals
、vals\u str\u list
和vals\u str
:
vals_str2 = ", ".join(["%({0})s".format(x) for x in cols])
cursor.execute("INSERT INTO song_table ({cols}) VALUES ({vals_str})".format(
cols = cols, vals_str = vals_str2), song)
印刷品:
insert into song_table (artist,title) values ('artist 1', 'song 1')
Psycopg将元组
调整为记录
,并执行Python的字符串替换所能完成的操作 您还可以使用字典插入多行。如果您有以下情况:
namedict = ({"first_name":"Joshua", "last_name":"Drake"},
{"first_name":"Steven", "last_name":"Foo"},
{"first_name":"David", "last_name":"Bar"})
您可以使用以下命令在字典中插入所有三行:
cur = conn.cursor()
cur.executemany("""INSERT INTO bar(first_name,last_name) VALUES (%(first_name)s, %(last_name)s)""", namedict)
cur.executemany
语句将自动迭代字典并对每一行执行INSERT查询
PS:此示例取自另一种从字典中查询mySQL或pgSQL的方法是使用构造%(dic_键)s
,它将被字典中的值替换,并由dic_键响应,如{dic_键:'dic值'}
工作完美,防止注入
已测试:Python 2.7
见下文:
# in_dict = {u'report_range': None, u'report_description': None, 'user_id': 6, u'rtype': None, u'datapool_id': 1, u'report_name': u'test suka 1', u'category_id': 3, u'report_id': None}
cursor.execute('INSERT INTO report_template (report_id, report_name, report_description, report_range, datapool_id, category_id, rtype, user_id) VALUES ' \
'(DEFAULT, %(report_name)s, %(report_description)s, %(report_range)s, %(datapool_id)s, %(category_id)s, %(rtype)s, %(user_id)s) ' \
'RETURNING "report_id";', in_dict)
#在dict={u'report\u range':None,u'report\u description':None,'user\u id':6,u'rtype':None,u'datapool\u id':1,u'report\u name':u'test suka 1',u'category\u id':3,u'report\u id':None}
cursor.execute('插入报表模板(报表id、报表名称、报表描述、报表范围、数据池id、类别id、rtype、用户id)值'\
“(默认,%(报表名称)s、%(报表描述)s、%(报表范围)s、%(数据池id)s、%(类别id)s、%(rtype)s、%(用户id)s)”\
“正在返回”报告id“,(在dict中)
输出:
插入报告模板(报告id、报告名称、报告描述、报告范围、数据池id、类别id、rtype、用户id)值(默认值,E'test suka 1',NULL、NULL、1、3、NULL、6)返回“报告id”;
新的sql
模块就是为此目的创建的,并添加到psycopg2 2.7版中。根据文件:
如果需要动态生成SQL查询(例如,动态选择表名),可以使用psycopg2.SQL模块提供的工具
文件中给出了两个示例:
在表中插入(“foo”、“bar”、“baz”)值(%s,%s,%s)
在表中插入(“foo”、“bar”、“baz”)值(%(foo)s、%(bar)s、%(baz)s)
尽管字符串串联会产生相同的结果,但根据psycopg2文档,不应将其用于此目的:
警告:从不、从不、从不使用Python字符串连接(+
)或字符串参数插值(%
)将变量传递给SQL查询字符串。甚至在枪口下也没有
Python具有某些内置功能,例如连接和列表,可以使用这些功能生成查询。此外,python字典还提供了键()和值(),可分别用于提取列名和列值这是我使用的方法,应该有效。
song = dict()
song['title'] = 'song 1'
song['artist'] = 'artist 1'
query = '''insert into song_table (''' +','.join(list(song.keys()))+''') values '''+ str(tuple(song.values()))
cursor.execute(query)
我还将用[cursor.mogrify(x)代替cols
,用vals\u str
代替cols
,以阻止SQL注入。我同意这肯定会增加额外的保护。稍微阅读一下psycopg2文档,mogrify
,可能没有必要,由于该方法的定义表明返回的字符串正是将发送到运行execute()方法或类似方法的数据库的字符串,因此我认为在调用execute
期间,列和%s
字符串将被mogrify
。我认为主要区别在于它是否提前执行了,在调用execute
之前,或在execute
过程中。如果以前执行过,它基本上只会在execute
运行期间返回相同的字符串,因为它已经被mogrified了。如果你想确切地知道发生了什么,比如说,你的日志,提前做可能会有好处。我不知道关于AsIs
。有趣的是--保存需要处理成倍的%s
s…我担心这可能会让用户由于转义不充分而容易受到注入攻击,但是-至少使用一个基本示例-单个撇号似乎可以正确转义。我没有时间测试更先进的注入技术,例如(或类似于)下面链接中描述的注入技术,因此与更标准的参数化技术相比,它们可能仍然是一个问题。为什么不直接使用song.values()作为值呢?:)如果我想获取插入行的id,那么该怎么办?获取mogrify需要一个psycopg2.extensions.cursor,但收到了一个'str'for insert_语句,这显然是一个字符串。嗨,vikas,有没有在循环中与cursor.execute()进行性能比较?这是一个非常非常糟糕的主意。引用psycopg文档:“绝不,绝不,绝不,绝不使用Python字符串连接(+)或字符串参数插值(%)将变量传递给SQL查询字符串。即使在枪口下也不行。”
names = ['foo', 'bar', 'baz']
q1 = sql.SQL("insert into table ({}) values ({})").format(
sql.SQL(', ').join(map(sql.Identifier, names)),
sql.SQL(', ').join(sql.Placeholder() * len(names)))
print(q1.as_string(conn))
q2 = sql.SQL("insert into table ({}) values ({})").format(
sql.SQL(', ').join(map(sql.Identifier, names)),
sql.SQL(', ').join(map(sql.Placeholder, names)))
print(q2.as_string(conn))
song = dict()
song['title'] = 'song 1'
song['artist'] = 'artist 1'
query = '''insert into song_table (''' +','.join(list(song.keys()))+''') values '''+ str(tuple(song.values()))
cursor.execute(query)