Funkcjonalny sposób:
W ten sposób pokazuje funkcje, które musisz skonfigurować, aby móc je wywołać w innym module. Usunąłem menedżera kontekstu, którego nie można używać z tym wzorcem funkcjonalnym, ponieważ jest on zamykany na końcu funkcji Open_Conn
. Więc open_conn
funkcja tworzy server
obiekt i obiekt bazy danych db
, zostaną wywołane jako następne w close_conn
zamykać w razie potrzeby.
#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_())
Sposób menedżera kontekstu:
Wzorzec funkcjonalny można ulepszyć, używając klasy menedżera kontekstu do automatycznej obsługi części otwierającej i zamykającej. Menedżer może zwrócić tylko db.cursor
aby wykonać zapytania, serwer pozostaje wewnątrz menedżera. Aby pobrać cursor
, przechwytujesz wartość zwracaną przez menedżera kontekstu w metodzie __enter__
używając jako :with OpenManager() as cursor:
.
Aby go utworzyć, możesz w zasadzie przenieść otwór kod wewnątrz metody __enter__
(wykonywane, gdy wywołasz menedżera kontekstu) i zamknięcie część wewnątrz metody __exit__
(wywoływane na końcu instrukcji with statement
blokować)
#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')
Ten wzorzec umożliwia wywołanie menedżera kontekstu w widżecie, wewnątrz with statement
jak poniżej :
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_())
Możesz również utworzyć połączenie za pomocą SSHTunnelForwarder
bezpośrednio w widgecie, aby tego uniknąć i użyj menedżera kontekstu dostarczonego przez klasę, a następnie utwórz połączenie z bazą danych w środku.
Pokazana powyżej klasa niestandardowa to tylko sposób na połączenie połączenia z serwerem i bazą danych w jednym kontekście, aby ułatwić, jeśli potrzebujesz tych połączeń w wielu miejscach w kodzie.