QSqlRelationalTableModel, пример из книги не работает
Не получается запустить пример из книги Прохоренок.
Строки не добавляются и не удаляются.
Может, кто-нибудь подскажет или свое напишет, буду очень благодарен.
from PyQt5 import QtCore, QtWidgets, QtSql
import sys
def addRecord():
stm.insertRow(stm.rowCount())
def delRecord():
stm.removeRow(tv.currentIndex().row())
stm.select()
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QWidget()
window.setWindowTitle("QRelationalSqlTableModel")
con = QtSql.QSqlDatabase.addDatabase('QSQLITE')
con.setDatabaseName('data.sqlite')
con.open()
stm = QtSql.QSqlRelationalTableModel(parent = window)
stm.setTable('good')
stm.setSort(1, QtCore.Qt.AscendingOrder)
# Задаем для поля категории связь с таблицей списка категорий
stm.setRelation(3, QtSql.QSqlRelation('category', 'id', 'catname'))
stm.select()
stm.setHeaderData(1, QtCore.Qt.Horizontal, 'Название')
stm.setHeaderData(2, QtCore.Qt.Horizontal, 'Кол-во')
stm.setHeaderData(3, QtCore.Qt.Horizontal, 'Категория')
vbox = QtWidgets.QVBoxLayout()
tv = QtWidgets.QTableView()
tv.setModel(stm)
tv.hideColumn(0)
tv.setColumnWidth(1, 150)
tv.setColumnWidth(2, 60)
tv.setColumnWidth(3, 150)
vbox.addWidget(tv)
btnAdd = QtWidgets.QPushButton("&Добавить запись")
btnAdd.clicked.connect(addRecord)
vbox.addWidget(btnAdd)
btnDel = QtWidgets.QPushButton("&Удалить запись")
btnDel.clicked.connect(delRecord)
vbox.addWidget(btnDel)
window.setLayout(vbox)
window.resize(430, 250)
window.show()
sys.exit(app.exec_())
Ответы (1 шт):
Я не читал данную книгу.
То что ваш пример написан не в ООП, немного настораживает.
Вы не привели скрипт, которые создает БД и необходимые таблицы.
Я попробовал представить для вас свой взгляд на вашу задачу.
Это примерный - вариант возможного решения, т.е. направление куда двигаться.
Обратите внимание:
БД называется
test_1318914.db;в методе
fillTable()создаются две таблицы -categoryиgood.
Название полей возможно не совпадает с вашими. После первого входа/выхода из приложения, закомментируйте вызов данного метода, чтобы таблицы не создавались при каждом входе в приложение:# self.fillTable()в таблице
categoryдве записи сid=1иid=2.
Если таблицаgoodсодержит ключи, которые относятся к несуществующим строкам в таблицеcategory, строки, содержащие недопустимые ключи, не будут отображаться в модели.
Пользователь или база данных несут ответственность за поддержание ссылочной целостности.
Класс QSqlRelationalTableModel предоставляет редактируемую модель данных
для одной таблицы базы данных с поддержкой внешнего ключа.
Больше https://doc.qt.io/qt-5/qsqlrelationaltablemodel.html
void QSqlRelationalTableModel::
setRelation(int column, const QSqlRelation &relation)Позволяет указанному столбцу быть внешним индексом, заданным отношением.
self.model.setRelation(2, QtSql.QSqlRelation(
"category",
"id",
"catname"))
Вызов
setRelation()указывает, что столбец2в таблицеgoodявляется внешним ключом, который сопоставляется с полемidтаблицыcategory, и что представление должно представлять пользователю полеcatname(наименование категории).
main.py
import sys
from PyQt5 import QtSql
from PyQt5.Qt import *
class Dialog(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle('Input Dialog')
self.line_edit_name = QLineEdit()
self.line_edit_quantity = QLineEdit()
self.line_edit_category = QLineEdit()
form_layout = QFormLayout()
form_layout.addRow('Name:', self.line_edit_name)
form_layout.addRow('quantity:', self.line_edit_quantity)
form_layout.addRow('category:', self.line_edit_category)
button_box = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
main_layout = QVBoxLayout(self)
main_layout.addLayout(form_layout)
main_layout.addWidget(button_box)
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.createConnection()
self.fillTable() # !!!
self.createModel()
self.initUI()
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
btnAdd = QPushButton("&Добавить запись")
btnAdd.clicked.connect(self.addRecord)
btnDel = QPushButton("&Удалить запись")
btnDel.clicked.connect(self.delRecord)
layout = QVBoxLayout(self.centralWidget)
layout.addWidget(self.view)
layout.addWidget(btnAdd)
layout.addWidget(btnDel)
def createConnection(self):
self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName("test_1318914.db") # !!! .db
if not self.db.open():
print("Cannot establish a database connection")
return False
def fillTable(self):
self.db.transaction()
q = QtSql.QSqlQuery()
# vvvvvvvv
q.exec_("DROP TABLE IF EXISTS category;")
q.exec_("CREATE TABLE category (id INT PRIMARY KEY, catname TEXT);")
q.exec_("INSERT INTO category VALUES (1, 'Расходники');")
q.exec_("INSERT INTO category VALUES (2, 'Носители');")
# vvvv
q.exec_("DROP TABLE IF EXISTS good;")
q.exec_("CREATE TABLE good (Name TEXT, Quantity INT, Category INT);")
q.exec_("INSERT INTO good VALUES ('Барабан для принтера', 8, 1);")
q.exec_("INSERT INTO good VALUES ('Бумага для принтера', 3, 1);")
q.exec_("INSERT INTO good VALUES ('Дискета', 10, 2);")
self.db.commit()
def createModel(self):
self.model = QtSql.QSqlRelationalTableModel()
self.model.setTable("good")
self.model.setHeaderData(0, Qt.Horizontal, "Название")
self.model.setHeaderData(1, Qt.Horizontal, "Кол-во")
self.model.setHeaderData(2, Qt.Horizontal, "Категория")
self.set_relation()
self.model.select()
def initUI(self):
self.view = QTableView()
self.view.setModel(self.model)
self.view.setColumnWidth(0, 150)
mode = QAbstractItemView.SingleSelection
self.view.setSelectionMode(mode)
def closeEvent(self, event):
if (self.db.open()):
self.db.close()
def set_relation(self):
self.model.setRelation(2, QtSql.QSqlRelation(
"category",
"id",
"catname"
))
def addRecord(self):
inputDialog = Dialog()
rez = inputDialog.exec()
if not rez:
msg = QMessageBox.information(self, 'Внимание', 'Диалог сброшен.')
return
name = inputDialog.line_edit_name.text()
quantity = inputDialog.line_edit_quantity.text()
category = inputDialog.line_edit_category.text()
if (not name) or (not quantity) or (not category):
msg = QMessageBox.information(self,
'Внимание', 'Заполните пожалуйста все поля.')
return
r = self.model.record()
r.setValue(0, name)
r.setValue(1, int(quantity))
r.setValue(2, int(category))
self.model.insertRecord(-1, r)
self.model.select()
def delRecord(self):
row = self.view.currentIndex().row()
if row == -1:
msg = QMessageBox.information(self,
'Внимание', 'Выберите запись для удаления.')
return
name = self.model.record(row).value(0)
quantity = self.model.record(row).value(1)
category = self.model.record(row).value(2)
inputDialog = Dialog()
inputDialog.setWindowTitle('Удалить запись ???')
inputDialog.line_edit_name.setText(name)
inputDialog.line_edit_quantity.setText(str(quantity))
inputDialog.line_edit_category.setText(str(category))
rez = inputDialog.exec()
if not rez:
msg = QMessageBox.information(self, 'Внимание', 'Диалог сброшен.')
return
self.model.setRelation(2, QtSql.QSqlRelation())
self.model.select()
self.model.removeRow(row)
self.set_relation()
self.model.select()
msg = QMessageBox.information(self, 'Успех', 'Запись удалена.')
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Example()
w.setWindowTitle("QRelationalSqlTableModel")
w.resize(430, 250)
w.show()
sys.exit(app.exec_())



