QSqlDatabase使用QSqlTableModel插入浮点数组



我试图插入一个数组到sql3中,并通过首先将它们转换为BLOB来检索它,但它没有插入任何东西到DB中,代码下面的一个小部件与QTableView使用pyqt模型模式

from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QTableView, QMessageBox, QAbstractItemView, QHeaderView
from PyQt6.QtSql import QSqlTableModel, QSqlDatabase, QSqlError, QSqlQuery
from PyQt6.QtCore import Qt, QSortFilterProxyModel
from numpy import array, frombuffer
from app.tools.cube_config import Config

class CubeDataTable(QWidget):
def __init__(self):
super(CubeDataTable, self).__init__()
self.lay = QVBoxLayout(self)
self.connect()
self.__model = QSqlTableModel()
self.__view = QTableView()
self.__proxy = QSortFilterProxyModel()
self.rows = 0
self._set_main_layout()
self.insert_data()
def _set_main_layout(self) -> None:
self._set_data_model()
self._set_table_view()
self.lay.addWidget(self.__view)
def _set_data_model(self) -> None:
self.__model.setTable('audio')
self.__model.setEditStrategy(QSqlTableModel.EditStrategy.OnManualSubmit)
self.__model.setHeaderData(0, Qt.Orientation.Horizontal, "ID")
self.__model.setHeaderData(1, Qt.Orientation.Horizontal, "Name")
self.__model.setHeaderData(2, Qt.Orientation.Horizontal, "Sample Rate")
self.__model.setHeaderData(3, Qt.Orientation.Horizontal, "Raw Frames")
self.__model.sort(1, Qt.SortOrder.DescendingOrder)
self.__model.select()
self.rows = self.__model.rowCount()
self.__proxy.setSourceModel(self.__model)
self.__proxy.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
self.__proxy.setFilterKeyColumn(1)
def _set_table_view(self) -> None:
self.__view.setModel(self.__proxy)
self.__view.setSortingEnabled(True)
self.__view.setAlternatingRowColors(True)
self.__view.setColumnHidden(0, True)
self.__view.verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
self.__view.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
self.__view.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
self.__view.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
self.__view.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
self.__view.resizeColumnsToContents()
self.__view.selectionModel().selectionChanged.connect(self._get_selected_row)
def _get_selected_row(self, selected, deselected):
index_entity = self.__view.selectionModel().selectedIndexes()
temp_entity = self.__view.selectionModel().model()
for index in sorted(index_entity):
d = temp_entity.data(index)
print(str(temp_entity.data(index)))
def insert_data(self):
try:
a = array([0.1, 0.2, 0.3])
self.__model.insertRows(self.rows, 1)
self.__model.setData(self.__model.index(self.rows, 1), 'foo')
self.__model.setData(self.__model.index(self.rows, 3), a.tobytes())
self.__model.submitAll()
self.rows += 1
except (Exception, QSqlError) as e:
self.__model.revertAll()
QSqlDatabase.database().rollback()
print("Error: " + str(e))

@staticmethod
def connect() -> bool:
config = Config.get('data')
conn = QSqlDatabase.addDatabase('QSQLITE')
conn.setHostName(config['host'])
conn.setPort(config['port'])
conn.setPassword(config['password'])
conn.setUserName(config['user'])
conn.setDatabaseName(config['database'])
if not conn.open():
QMessageBox.critical(QMessageBox(), "Error", "Error: %s" % conn.lastError().text())
return False
cursor = QSqlQuery()
cursor.exec(
"""
CREATE TABLE audio (
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
name VARCHAR(40) NOT NULL,
sampleRate INTEGER,
rawFrames BLOB                
)
"""
)
return True

在处理Qt时,重要的是要记住它们的python绑定(PyQt和PySide)使用自动类型转换,并且可以接受变量("union"在Qt端使用QVariant

虽然大多数转换都是在python端透明地完成的,但对于特殊情况,包括数据库类中的原始数据,可能不是这样,因为Qt必须更具体地知道数据类型,以便正确地将其提交给数据库。

一般规则是,如果数据以字节形式存储,通常需要使用QByteArray:

self.__model.setData(self.__model.index(self.rows, 3), QByteArray(a.tobytes()))

请注意,如果您需要以人类可读的形式显示数组,您还需要一个可以处理它的特定委托。为此,通常实现QStyledItemDelegate的displayText()并将字节数组转换为它的可打印版本就足够了:

class Delegate(QStyledItemDelegate):        
def displayText(self, text, locale):
if isinstance(text, QByteArray):
try:
res = frombuffer(text.data())
return str(res)
except:
pass
return super().displayText(text, locale)

然后,设置所需列的委托:

self.__view.setItemDelegateForColumn(3, Delegate(self.__view))

注意,通常最好避免使用"static"参考self.rows,因为当您在其他地方更改模型时,或者在更新不成功的情况下,可能会忘记更新它;相反,只需使用动态getterrowCount(),并记住在使用数据库模型时检查函数是否成功总是很重要的。

def insert_data(self):
a = array([0.1, 0.2, 0.3])
row = self.__model.rowCount()
if not self.__model.insertRow(row):
# some warning using self.__model.lastError(), then return
self.__model.setData(self.__model.index(row, 1), 'foo')
# ...
if not self.__model.submitAll():
# as above

最新更新