Python 在另一个脚本上引用数据库连接

Python referencing database connection on another script

我正在深入学习 Python,同时尝试制作一个应用程序,使用存储在 MySQL/MariaDB 上的数据,我几乎处于可以取得一些良好进展的阶段与项目。我可以通过 SSH 连接到我的数据库,并从 python 脚本检索数据,但我现在希望在 GUI 框中显示该数据。我面临的挑战之一是我有两个单独的脚本来处理连接,一个用于打开,一个用于关闭,我的理论是只有数据访问才需要连接。我已经使用 PyQT5 创建了各种 GUI 和 windows,特别是我希望填充 QtTableWidget。我的脚本目前没有给我任何错误,但它也没有在 table 小部件中显示数据。我的直觉是它没有在打开的连接脚本上正确引用数据库,因此没有要传递的数据,但我正在努力确定有效 google 搜索所需的术语。

我的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()

任何人都可以帮助我确定为什么我没有在 table 小部件中获取数据吗? 非常感谢

功能方式:

这种方式显示了您需要设置的功能,以便能够在另一个模块中调用它们。我删除了不能与此功能模式一起使用的上下文管理器,因为它在函数结束时关闭 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_())

上下文管理器方式:

可以通过使用上下文管理器 class 自动处理打开和关闭部分来改进功能模式。管理器可以 return 只有 db.cursor 来执行查询,服务器保留在管理器内部。要获得 cursor,您可以使用 as 方法 __enter__ 中的上下文管理器捕获值 return : with OpenManager() as cursor:.

要创建它,基本上,您可以在方法 __enter__ 中移动 opening 代码(在调用上下文管理器时执行)和 closing 方法 __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 的连接以避免这种情况,并使用 class 提供的上下文管理器,然后在其中创建数据库连接。

上面显示的自定义 class 只是一种在一个上下文中混合与服务器和数据库的连接的方法,以便在您的代码中的许多地方需要这些连接时变得容易。