我正在使用REST
和Flask-Rebar
在Python 3.6中开发一个PostgreSQL
API,尝试使用psycopg2
同时执行一些查询时遇到了麻烦。
更具体地说,我执行一个查询,并要求此查询中的id
值用于下一个查询。第一个查询成功返回期望值,但是调用后续查询的函数甚至没有执行。
以下是负责调用查询功能的功能:
psql = PostgresHandler()
user_ids = [1, 5, 9]
horse = {"name": "Adam", "age": 400}
def createHorseQuery(user_ids, horse):
time_created = strftime("%Y-%m-%dT%H:%M:%SZ")
fields, values = list(), list()
for key, val in horse.items():
fields.append(key)
values.append(val)
fields.append('time_created')
values.append(time_created)
fields = str(fields).replace('[', '(').replace(']', ')').replace("'", "")
values = str(values).replace('[', '(').replace(']', ')')
create_horse_query = f"INSERT INTO horse {fields} VALUES {values} RETURNING horse_id;"
horse_id = None
for h_id in psql.queryDatabase(create_horse_query, returnInsert=True):
horse_id = h_id
link_user_query = ''
for u_id in user_ids:
link_user_query += f"INSERT INTO user_to_horse (user_id, horse_id) VALUES ({u_id}, {horse_id['horse_id']});"
psql.queryDatabase(link_user_query)
return horse_id, 201
这是PostgresHandler()
类,其中包含函数queryDatabase
:
class PostgresHandler(object):
def __init__(self):
self.connectToDatabase()
def connectToDatabase(self):
self.connection = psycopg2.connect(
host = '...',
user = '...',
password = '...',
database = '...'
)
def queryDatabase(self, query, returnInsert=False):
cursor = self.connection.cursor(cursor_factory=RealDictCursor)
cursor.execute(query)
if "SELECT" in query.upper():
for result in cursor.fetchall():
yield result
elif "INSERT" in query.upper():
if returnInsert:
for result in cursor.fetchall():
yield result
self.connection.commit()
cursor.close()
我可以通过手动查询数据库并与返回值psql.queryDatabase(create_horse_query, returnInsert=True)
进行比较来验证h_id
操作是否成功。
我可以验证是否创建了link_user_query
并包含打印所期望的user_ids
和horse_id
。我知道所生成的查询是可以的,因为我已经在数据库中对此进行了手动测试。
在psql.queryDatabase(link_user_query)
函数的非常顶部处,似乎从未真正调用在行queryDatabase
上调用的函数作为打印语句。 / p>
我尝试在两个查询函数调用之间进行延迟,并与每个函数调用初始化一个新的连接,但许多其他事情无济于事,我对此感到很沮丧。任何见解都将不胜感激。
编辑:仅供参考,createHorseQuery
函数成功返回并按预期显示两个返回值。
答案 0 :(得分:1)
queryDatabase
是生成器,因为它包含一个yield语句。生成器仅在您对其进行迭代时才实际执行操作(即导致__next__()
被调用)。请考虑以下内容:
def gen():
print("Gen is running!")
yield "Gen yielded: hello"
print("Gen did: commit")
print("***Doing stuff with b***")
b = gen()
for a in b:
print(a)
print("***Doing stuff with c***")
c = gen()
print("***Done***")
输出为:
***Doing stuff with b***
Gen is running!
Gen yielded: hello
Gen did: commit
***Doing stuff with c***
***Done***
当我们调用gen()
创建c
时,我们实际上并没有运行它,只是将其实例化为生成器。
我们可以通过多次调用__next__()
来强制其运行:
c.__next__()
try:
c.__next__()
except StopIteration:
print("Iteration is over!")
输出:
Gen is running!
Gen did: commit
Iteration is over!
但是,实际上,您可能不应该在从未打算从中使用yield
的情况下使用这样的生成器。您可以考虑添加一个新函数,该函数不是名为insertSilently
(或类似名称)的生成器。