我想在定制类中使用连接和游标类。我还想继承与连接和游标类关联的所有方法。我对此进行了一些研究,发现docs和这个question与我的问题有关。我有一些部分起作用的代码。即我可以插入和更新数据库。但是,我无法从数据库中进行选择,因为即使该行在数据库中,这样做也不会返回任何内容。这是我的代码
from datetime import datetime, timedelta
import psycopg2
import psycopg2.extensions
class DataBase():
"""A class used to create tables in the database. Inherits from
psycopg2.extensions.connection in order to gain access to the cursor,
commit, close, and many other features from the pyscopg module.
"""
def __init__(self):
self.my_connection = psycopg2.connect(database="public", user="public",
password="general", host="127.0.0.1",
port="5432")
self.my_cursor = self.my_connection.cursor()
def query_database(self, sql_statement, *args):
return self.my_cursor.execute(sql_statement, *args)
def commit_query(self):
return self.my_connection.commit()
def fetch_one(self, sql_statement, *args):
result = self.query_database(sql_statement, *args)
if result is None:
return False
return result.fetchone()
def fetch_all(self, sql_statement, *args):
result = self.query_database(sql_statement, *args)
if result is None:
return False
return result.fetchall()
def __del__(self):
self.my_cursor.close()
self.my_connection.close()
############################################################################
class CreateTables(DataBase):
def create_user_table(self):
"""Helper function used to create the user_table"""
sql_statement = '''CREATE TABLE IF NOT EXISTS USERS
(ID SERIAL PRIMARY KEY,
FIRSTNAME TEXT NOT NULL,
LASTNAME TEXT NOT NULL,
USERNAME TEXT NOT NULL UNIQUE,
EMAIL TEXT NOT NULL UNIQUE,
PASSWORD TEXT NOT NULL,
DATETIMEREGISTERED TIMESTAMP NOT NULL);'''
user_table = DataBase.query_database(self, sql_statement)
DataBase.commit_query(self)
return user_table
def create_entries_table(self):
"""Helper function used to create an entries table."""
sql_statement = '''CREATE TABLE IF NOT EXISTS ENTRIES
(ID SERIAL PRIMARY KEY,
TITLE TEXT NOT NULL,
DRINK TEXT NOT NULL,
DATEOFORDER TIMESTAMP NOT NULL,
TIMETODELIVERY TIMESTAMP NOT NULL,
SETREMINDER TIMESTAMP NOT NULL,
USERID INT REFERENCES USERS ON DELETE CASCADE);'''
entries_table = DataBase.query_database(self, sql_statement)
DataBase.commit_query(self)
print("entries table created.")
return entries_table
# test = CreateTables() This is working well
# print(test.create_entries_table())
#####################################################################
class OperateDatabase(CreateTables):
def create_user(self, email, username, *args):
"""Helper function used to create a user"""
sql_statement = """SELECT ID FROM USERS WHERE EMAIL = %s OR
USERNAME = %s;"""
user_in_database = CreateTables.fetch_one(self, sql_statement,
(email, username,))
print("the user in database is :>>", user_in_database)
sql_statement2 = """INSERT INTO USERS (FIRSTNAME, LASTNAME, USERNAME,
EMAIL, PASSWORD, DATETIMEREGISTERED)
VALUES (%s, %s, %s, %s, %s, %s);"""
if not user_in_database:
CreateTables.query_database(self,sql_statement2, *args)
CreateTables.commit_query(self)
return True
return False
data = ("Jkdai", "Jkdal", "Jkdai", "jkdai@gmail.com", "password", datetime.now())
test = OperateDatabase()
print(test.create_user("jkdai@gmail.com", "jkdai", data))
#Inserts the user the very first time implying the insert statement is working
#raises an integrity error the second time implying the select statement is not working.
#Also the print statement defaults to false when it is supposed to return the user's id.
答案 0 :(得分:2)
cursor.execute()
返回供应商定义的值(在db-api规范中未指定),而对于pyscopg2,它实际上被记录为确实返回了None
,因此:
def query_database(self, sql_statement, *args):
return self.my_cursor.execute(sql_statement, *args)
def fetch_one(self, sql_statement, *args):
result = self.query_database(sql_statement, *args)
if result is None:
return False
return result.fetchone()
显然不会按您预期的那样工作。您可以改为从self.my_cursor()
返回query_database()
,即:
def query_database(self, sql_statement, *args):
self.my_cursor.execute(sql_statement, *args)
return self.my_cursor
def fetch_one(self, sql_statement, *args):
cursor = self.query_database(sql_statement, *args)
return cursor.fetchone()
但是该代码有一个根本缺陷,那就是它不能重入(也不是线程安全的FWIW)。实际上,您的类不应将游标存储为状态的一部分,而应一遍又一遍地重复使用(db-api游标并不意味着以这种方式使用),而应为每个操作创建一个新的游标(这是缩进的用法)。
此外,您不要依靠__del__(self)
来关闭连接。 __del__()
方法不是正确的C ++ / Java样式终结器,甚至在收集对象时也不建议调用该方法。实际上,尝试将数据库连接和游标包装在类中通常不是一个好主意,至少不是这样。