Функционалният начин:
По този начин се показват функциите, които трябва да настроите, за да можете да ги извиквате в друг модул. Премахнах контекстния мениджър, който не може да се използва с този функционален модел, тъй като се затваря в края на функцията 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
директно в изпълнимия модул, за да избегнете това и използвайте контекстния мениджър, предоставен от класа, след което създайте връзката с базата данни вътре.
Персонализираният клас, показан по-горе, е просто начин да смесите връзката към сървъра и към базата данни в един контекст, за да улесните, ако имате нужда от тези връзки на много места във вашия код.