我正在尝试使用存储在MySQL / MariaDB上的数据创建应用程序时学习Python的深度,我几乎处于可以在项目上取得一些进展的阶段。我可以通过SSH连接到我的数据库,并从python脚本中检索数据,但我现在希望在GUI框中显示该数据。我面临的挑战之一是我有两个独立的脚本来处理连接,一个打开,一个打开,我的理论是只需要一个连接来进行数据访问。我已经使用PyQT5来创建各种GUI和窗口,特别是我希望填充QtTableWidget。我目前的脚本目前没有给我任何错误,但它也没有显示表格小部件中的数据。我的预感是,它没有在开放连接脚本上正确引用数据库,因此无法传递数据,但我很难确定有效谷歌搜索所需的术语。
我的OpenConn.py如下:
import MySQLdb
from sshtunnel import SSHTunnelForwarder
def Open_Conn():
with SSHTunnelForwarder(
('192.168.0.10', 22),
ssh_password="xxx",
ssh_username="xxx",
remote_bind_address=('localhost', 3306)) as server:
db = MySQLdb.connect(host='localhost',
port=server.local_bind_port,
user='xxx',
passwd='xxx',
db='DBNAME')
cursor = db.cursor()
if __name__ == '__main__':
Open_Conn()
我的main.py如下:
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from ViewClientsUI import Ui_ViewClients
from OpenConn import Open_Conn
class ViewClientsWindow(QtWidgets.QDialog, Ui_ViewClients):
def __init__(self):
super(ViewClientsWindow, self).__init__()
self._new_window = None
self.setupUi(self)
def data_load():
with OpenConn.Open_Conn:
connection = OpenConn.Open_Conn()
query = "SELECT * FROM Clients"
result = connection.execute(query)
self.tableWidget.setRowCount(0)
for row_number, row_data in enumerate(result):
self.tableWidget.insertRow(row_number)
for column_number, data in enumerate(row_data):
self.tableWidget.setItem(row_number, column_number, QtWidgets.QTableWidgetItem(str(data)))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
gui = ViewClientsWindow()
gui.show()
app.exec_()
Open_Conn()
任何人都可以帮助我确定为什么我没有在表格小部件中获取数据? 非常感谢提前
答案 0 :(得分:2)
这种方式显示了您需要设置的功能,以便能够在另一个模块中调用它们。我删除了无法与此功能模式一起使用的上下文管理器,因为它在函数Open_Conn
的末尾关闭。因此open_conn
函数创建了一个server
对象,而数据库对象db
,它们将在close_conn
中被调用,以便在必要时关闭。
#OpenConn.py
import MySQLdb
from sshtunnel import SSHTunnelForwarder
def open_conn():
server = SSHTunnelForwarder(
('192.168.0.10', 22),
ssh_password="xxx",
ssh_username="xxx",
remote_bind_address=('localhost', 3306))
server.start()
print('opening server : OK')
db = MySQLdb.connect(host='localhost',
port=server.local_bind_port,
user='xxx',
passwd='xxx',
db='DBNAME')
print('opening database : OK')
return (server, db)
def close_conn(server, db):
db.close()
server.stop()
print('closing connection : OK')
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from ViewClientsUI import Ui_ViewClients
from OpenConn import open_conn, close_conn
class ViewClientsWindow(QtWidgets.QDialog, Ui_ViewClients):
def __init__(self):
super(ViewClientsWindow, self).__init__()
self._new_window = None
self.setupUi(self)
self.data_load()
def data_load(self):
server, db = open_conn()
cursor = db.cursor()
query = "SELECT * FROM Clients"
cursor.execute(query)
results = cursor.fetchall()
self.tableWidget.setRowCount(0)
for row_number, row_data in enumerate(results):
self.tableWidget.insertRow(row_number)
for column_number, data in enumerate(row_data):
self.tableWidget.setItem(row_number, column_number, QtWidgets.QTableWidgetItem(str(data)))
close_conn(server, db)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
gui = ViewClientsWindow()
gui.show()
sys.exit(app.exec_())
通过使用上下文管理器类自动处理打开和关闭部分,可以改进功能模式。管理员只能返回db.cursor
来执行查询,服务器保留在管理器内。要获得cursor
,您可以使用作为:__enter__
来抓住方法with OpenManager() as cursor:
中的上下文管理器返回值。
要创建它,基本上,您可以在方法__enter__
中移动开始代码(当您调用上下文管理器时执行)和关闭部分在方法__exit__
内(在with statement
块的末尾调用)
#OpenConn.py
import MySQLdb
from sshtunnel import SSHTunnelForwarder
class OpenManager(object):
def __init__(self):
self.server =None
self.db = None
# here you could define some parameters and call them next
def __enter__(self):
self.server = SSHTunnelForwarder(
('192.168.0.10', 22),
ssh_password="xxx",
ssh_username="xxx",
remote_bind_address=('localhost', 3306))
self.server.start()
print('opening server : OK')
self.db = MySQLdb.connect(host='localhost',
port=self.server.local_bind_port,
user='xxx',
passwd='xxx',
db='DBNAME')
print('opening database : OK')
return self.db.cursor() #
def __exit__(self, type, value, traceback):
self.db.close()
self.server.stop()
print('closing connection : OK')
此模式允许您在with statement
内部调用窗口小部件中的上下文管理器,如下所示:
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from ViewClientsUI import Ui_ViewClients
from OpenConn import OpenManager
class ViewClientsWindow(QtWidgets.QDialog, Ui_ViewClients):
def __init__(self):
super(ViewClientsWindow, self).__init__()
self._new_window = None
self.setupUi(self)
self.data_load()
def data_load(self):
with OpenManager() as cursor:
query = "SELECT * FROM Clients"
cursor.execute(query)
results = cursor.fetchall()
self.tableWidget.setRowCount(0)
for row_number, row_data in enumerate(results):
self.tableWidget.insertRow(row_number)
for column_number, data in enumerate(row_data):
self.tableWidget.setItem(row_number, column_number, QtWidgets.QTableWidgetItem(str(data)))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
gui = ViewClientsWindow()
gui.show()
sys.exit(app.exec_())
您还可以直接在窗口小部件中创建与SSHTunnelForwarder
的连接以避免这种情况,并使用该类提供的上下文管理器,然后在其中创建数据库连接。
上面显示的自定义类只是一种将连接与服务器和数据库混合在一个上下文中的方法,以便在代码中的许多位置需要这些连接时轻松实现。